ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
const
char
* descriptor,
size_t
hash,
Handle<mirror::ClassLoader> class_loader,
const
DexFile& dex_file,
const
dex::ClassDef& dex_class_def) {
ScopedDefiningClass sdc(self);
StackHandleScope<3> hs(self);
metrics::AutoTimer timer{GetMetrics()->ClassLoadingTotalTime()};
metrics::AutoTimer timeDelta{GetMetrics()->ClassLoadingTotalTimeDelta()};
auto
klass = hs.NewHandle<mirror::Class>(nullptr);
if
(UNLIKELY(!init_done_)) {
if
(
strcmp
(descriptor,
"Ljava/lang/Object;"
) == 0) {
klass.Assign(GetClassRoot<mirror::Object>(
this
));
}
else
if
(
strcmp
(descriptor,
"Ljava/lang/Class;"
) == 0) {
klass.Assign(GetClassRoot<mirror::Class>(
this
));
}
else
if
(
strcmp
(descriptor,
"Ljava/lang/String;"
) == 0) {
klass.Assign(GetClassRoot<mirror::String>(
this
));
}
else
if
(
strcmp
(descriptor,
"Ljava/lang/ref/Reference;"
) == 0) {
klass.Assign(GetClassRoot<mirror::Reference>(
this
));
}
else
if
(
strcmp
(descriptor,
"Ljava/lang/DexCache;"
) == 0) {
klass.Assign(GetClassRoot<mirror::DexCache>(
this
));
}
else
if
(
strcmp
(descriptor,
"Ldalvik/system/ClassExt;"
) == 0) {
klass.Assign(GetClassRoot<mirror::ClassExt>(
this
));
}
}
if
(class_loader == nullptr &&
Runtime::Current()->IsAotCompiler() &&
DenyAccessBasedOnPublicSdk(descriptor)) {
ObjPtr<mirror::Throwable> pre_allocated =
Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
self->SetException(pre_allocated);
return
sdc.Finish(nullptr);
}
if
(!self->CanLoadClasses()) {
ObjPtr<mirror::Throwable> pre_allocated =
Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
self->SetException(pre_allocated);
return
sdc.Finish(nullptr);
}
ScopedTrace trace(descriptor);
if
(klass == nullptr) {
if
(CanAllocClass()) {
klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
}
else
{
return
sdc.Finish(nullptr);
}
}
if
(UNLIKELY(klass == nullptr)) {
self->AssertPendingOOMException();
return
sdc.Finish(nullptr);
}
DexFile
const
* new_dex_file = nullptr;
dex::ClassDef
const
* new_class_def = nullptr;
Runtime::Current()->GetRuntimeCallbacks()->ClassPreDefine(descriptor,
klass,
class_loader,
dex_file,
dex_class_def,
&new_dex_file,
&new_class_def);
if
(self->IsExceptionPending()) {
return
sdc.Finish(nullptr);
}
ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get());
if
(dex_cache == nullptr) {
self->AssertPendingException();
return
sdc.Finish(nullptr);
}
klass->SetDexCache(dex_cache);
SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get());
if
(UNLIKELY(!init_done_)) {
if
(
strcmp
(descriptor,
"Ljava/lang/String;"
) == 0) {
klass->SetStringClass();
}
}
ObjectLock<mirror::Class> lock(self, klass);
klass->SetClinitThreadId(self->GetTid());
klass->SetIfTable(GetClassRoot<mirror::Object>(
this
)->GetIfTable());
ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);
if
(existing != nullptr) {
return
sdc.Finish(EnsureResolved(self, descriptor, existing));
}
LoadClass(self, *new_dex_file, *new_class_def, klass);
if
(self->IsExceptionPending()) {
VLOG(class_linker) << self->GetException()->Dump();
if
(!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return
sdc.Finish(nullptr);
}
CHECK(!klass->IsLoaded());
if
(!LoadSuperAndInterfaces(klass, *new_dex_file)) {
if
(!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return
sdc.Finish(nullptr);
}
CHECK(klass->IsLoaded());
Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(klass);
CHECK(!klass->IsResolved());
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)) {
if
(!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return
sdc.Finish(nullptr);
}
self->AssertNoPendingException();
CHECK(h_new_class != nullptr) << descriptor;
CHECK(h_new_class->IsResolved()) << descriptor <<
" "
<< h_new_class->GetStatus();
if
(Runtime::Current()->GetInstrumentation()->EntryExitStubsInstalled()) {
DCHECK_EQ(self->GetState(), ThreadState::kRunnable);
Runtime::Current()->GetInstrumentation()->InstallStubsForClass(h_new_class.Get());
}
Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(klass, h_new_class);
jit::Jit::NewTypeLoadedIfUsingJit(h_new_class.Get());
return
sdc.Finish(h_new_class);
}