mirror::Class* ClassLinker::DefineClass(Thread* self,
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
StackHandleScope<3> hs(self);
auto klass = hs.NewHandle<mirror::Class>(nullptr);
......
// Get the real dex file. This will return the input if there aren't any callbacks or they do
// nothing.
DexFile const* new_dex_file = nullptr;
DexFile::ClassDef const* new_class_def = nullptr;
// TODO We should ideally figure out some way to move this after we get a lock on the klass so it
// will only be called once.
Runtime::Current()->GetRuntimeCallbacks()->ClassPreDefine(descriptor,
klass,
class_loader,
dex_file,
dex_class_def,
&new_dex_file,
&new_class_def);
// Check to see if an exception happened during runtime callbacks. Return if so.
if (self->IsExceptionPending()) {
return nullptr;
}
ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get());
if (dex_cache == nullptr) {
self->AssertPendingException();
return nullptr;
}
klass->SetDexCache(dex_cache);
SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get());
// Mark the string class by setting its access flag.
if (UNLIKELY(!init_done_)) {
if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
klass->SetStringClass();
}
}
ObjectLock<mirror::Class> lock(self, klass);
klass->SetClinitThreadId(self->GetTid());
// Make sure we have a valid empty iftable even if there are errors.
klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
// Add the newly loaded class to the loaded classes table.
ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);
if (existing != nullptr) {
// We failed to insert because we raced with another thread. Calling EnsureResolved may cause
// this thread to block.
return EnsureResolved(self, descriptor, existing);
}
// Load the fields and other things after we are inserted in the table. This is so that we don't
// end up allocating unfree-able linear alloc resources and then lose the race condition. The
// other reason is that the field roots are only visited from the class table. So we need to be
// inserted before we allocate / fill in these fields.
LoadClass(self, *new_dex_file, *new_class_def, klass);
if (self->IsExceptionPending()) {
VLOG(class_linker) << self->GetException()->Dump();
// An exception occured during load, set status to erroneous while holding klass' lock in case
// notification is necessary.
if (!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
}
return nullptr;
}
// Finish loading (if necessary) by finding parents
CHECK(!klass->IsLoaded());
if (!LoadSuperAndInterfaces(klass, *new_dex_file)) {
// Loading failed.
if (!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
}
return nullptr;
}
CHECK(klass->IsLoaded());
// At this point the class is loaded. Publish a ClassLoad event.
// Note: this may be a temporary class. It is a listener's responsibility to handle this.
Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(klass);
// Link the class (if necessary)
CHECK(!klass->IsResolved());
// TODO: Use fast jobjects?
auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
MutableHandle<mirror::Class> h_new_class = hs.NewHandle<mirror::Class>(nullptr);
if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {
// Linking failed.
if (!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
}
return nullptr;
}
self->AssertNoPendingException();
CHECK(h_new_class != nullptr) << descriptor;
CHECK(h_new_class->IsResolved() && !h_new_class->IsErroneousResolved()) << descriptor;
// Instrumentation may have updated entrypoints for all methods of all
// classes. However it could not update methods of this class while we
// were loading it. Now the class is resolved, we can update entrypoints
// as required by instrumentation.
if (Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {
// We must be in the kRunnable state to prevent instrumentation from
// suspending all threads to update entrypoints while we are doing it
// for this class.
DCHECK_EQ(self->GetState(), kRunnable);
Runtime::Current()->GetInstrumentation()->InstallStubsForClass(h_new_class.Get());
}
/*
* We send CLASS_PREPARE events to the debugger from here. The
* definition of "preparation" is creating the static fields for a
* class and initializing them to the standard default values, but not
* executing any code (that comes later, during "initialization").
*
* We did the static preparation in LinkClass.
*
* The class has been prepared and resolved but possibly not yet verified
* at this point.
*/
Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(klass, h_new_class);
// Notify native debugger of the new class and its layout.
jit::Jit::NewTypeLoadedIfUsingJit(h_new_class.Get());
return h_new_class.Get();
}
|