Fix UnstartedRunime leaking local reference.
And assert that class initialization in CompilerDriver
does not leave any local references alive.
Test: m test-art-host-gtest
Change-Id: Icd6a141da340d21d0103308a9e056009eb86f485
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index c94c57f..def5af9 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -2119,7 +2119,7 @@
if (klass != nullptr) {
if (!SkipClass(manager_->GetClassLoader(), dex_file, klass.Get())) {
- TryInitializeClass(klass, class_loader);
+ TryInitializeClass(soa.Self(), klass, class_loader);
}
manager_->GetCompiler()->stats_->AddClassStatus(klass->GetStatus());
}
@@ -2128,14 +2128,15 @@
}
// A helper function for initializing klass.
- void TryInitializeClass(Handle<mirror::Class> klass, Handle<mirror::ClassLoader>& class_loader)
+ void TryInitializeClass(Thread* self,
+ Handle<mirror::Class> klass,
+ Handle<mirror::ClassLoader>& class_loader)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile& dex_file = klass->GetDexFile();
const dex::ClassDef* class_def = klass->GetClassDef();
const dex::TypeId& class_type_id = dex_file.GetTypeId(class_def->class_idx_);
const char* descriptor = dex_file.StringDataByIdx(class_type_id.descriptor_idx_);
- ScopedObjectAccessUnchecked soa(Thread::Current());
- StackHandleScope<3> hs(soa.Self());
+ StackHandleScope<3> hs(self);
ClassLinker* const class_linker = manager_->GetClassLinker();
Runtime* const runtime = Runtime::Current();
const CompilerOptions& compiler_options = manager_->GetCompiler()->GetCompilerOptions();
@@ -2160,7 +2161,7 @@
if (klass->IsVerified()) {
// Attempt to initialize the class but bail if we either need to initialize the super-class
// or static fields.
- class_linker->EnsureInitialized(soa.Self(), klass, false, false);
+ class_linker->EnsureInitialized(self, klass, false, false);
old_status = klass->GetStatus();
if (!klass->IsInitialized()) {
// We don't want non-trivial class initialization occurring on multiple threads due to
@@ -2172,18 +2173,18 @@
// We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
// than use a special Object for the purpose we use the Class of java.lang.Class.
Handle<mirror::Class> h_klass(hs.NewHandle(klass->GetClass()));
- ObjectLock<mirror::Class> lock(soa.Self(), h_klass);
+ ObjectLock<mirror::Class> lock(self, h_klass);
// Attempt to initialize allowing initialization of parent classes but still not static
// fields.
// Initialize dependencies first only for app or boot image extension,
// to make TryInitializeClass() recursive.
bool try_initialize_with_superclasses =
- is_boot_image ? true : InitializeDependencies(klass, class_loader, soa.Self());
+ is_boot_image ? true : InitializeDependencies(klass, class_loader, self);
if (try_initialize_with_superclasses) {
- class_linker->EnsureInitialized(soa.Self(), klass, false, true);
+ class_linker->EnsureInitialized(self, klass, false, true);
// It's OK to clear the exception here since the compiler is supposed to be fault
// tolerant and will silently not initialize classes that have exceptions.
- soa.Self()->ClearException();
+ self->ClearException();
}
// Otherwise it's in app image or boot image extension but superclasses
// cannot be initialized, no need to proceed.
@@ -2214,10 +2215,10 @@
// <clinit> at compile time.
can_init_static_fields =
ClassLinker::kAppImageMayContainStrings &&
- !soa.Self()->IsExceptionPending() &&
+ !self->IsExceptionPending() &&
!compiler_options.GetDebuggable() &&
(compiler_options.InitializeAppImageClasses() ||
- NoClinitInDependency(klass, soa.Self(), &class_loader));
+ NoClinitInDependency(klass, self, &class_loader));
// TODO The checking for clinit can be removed since it's already
// checked when init superclass. Currently keep it because it contains
// processing of intern strings. Will be removed later when intern strings
@@ -2236,17 +2237,17 @@
// TransactionAbortError is not initialized ant not in boot image, needed only by
// compiler and will be pruned by ImageWriter.
Handle<mirror::Class> exception_class =
- hs.NewHandle(class_linker->FindClass(soa.Self(),
+ hs.NewHandle(class_linker->FindClass(self,
Transaction::kAbortExceptionSignature,
class_loader));
bool exception_initialized =
- class_linker->EnsureInitialized(soa.Self(), exception_class, true, true);
+ class_linker->EnsureInitialized(self, exception_class, true, true);
DCHECK(exception_initialized);
// Run the class initializer in transaction mode.
runtime->EnterTransactionMode(is_app_image, klass.Get());
- bool success = class_linker->EnsureInitialized(soa.Self(), klass, true, true);
+ bool success = class_linker->EnsureInitialized(self, klass, true, true);
// TODO we detach transaction from runtime to indicate we quit the transactional
// mode which prevents the GC from visiting objects modified during the transaction.
// Ensure GC is not run so don't access freed objects when aborting transaction.
@@ -2265,8 +2266,8 @@
old_status = klass->GetStatus();
}
} else {
- CHECK(soa.Self()->IsExceptionPending());
- mirror::Throwable* exception = soa.Self()->GetException();
+ CHECK(self->IsExceptionPending());
+ mirror::Throwable* exception = self->GetException();
VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
<< exception->Dump();
std::ostream* file_log = manager_->GetCompiler()->
@@ -2275,7 +2276,7 @@
*file_log << descriptor << "\n";
*file_log << exception->Dump() << "\n";
}
- soa.Self()->ClearException();
+ self->ClearException();
runtime->RollbackAllTransactions();
CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
}
@@ -2298,16 +2299,16 @@
// Clear exception in case EnsureInitialized has caused one in the code above.
// It's OK to clear the exception here since the compiler is supposed to be fault
// tolerant and will silently not initialize classes that have exceptions.
- soa.Self()->ClearException();
+ self->ClearException();
// If the class still isn't initialized, at least try some checks that initialization
// would do so they can be skipped at runtime.
if (!klass->IsInitialized() && class_linker->ValidateSuperClassDescriptors(klass)) {
old_status = ClassStatus::kSuperclassValidated;
} else {
- soa.Self()->ClearException();
+ self->ClearException();
}
- soa.Self()->AssertNoPendingException();
+ self->AssertNoPendingException();
}
}
if (old_status == ClassStatus::kInitialized) {
@@ -2319,6 +2320,11 @@
// Back up the status before doing initialization for static encoded fields,
// because the static encoded branch wants to keep the status to uninitialized.
manager_->GetCompiler()->RecordClassStatus(ref, old_status);
+
+ if (kIsDebugBuild) {
+ // Make sure the class initialization did not leave any local references.
+ self->GetJniEnv()->AssertLocalsEmpty();
+ }
}
private:
@@ -2438,7 +2444,7 @@
StackHandleScope<1> hs(self);
Handle<mirror::Class> super_class = hs.NewHandle(klass->GetSuperClass());
if (!super_class->IsInitialized()) {
- this->TryInitializeClass(super_class, class_loader);
+ this->TryInitializeClass(self, super_class, class_loader);
if (!super_class->IsInitialized()) {
return false;
}
@@ -2451,7 +2457,7 @@
StackHandleScope<1> hs(self);
Handle<mirror::Class> iface = hs.NewHandle(klass->GetIfTable()->GetInterface(i));
if (iface->HasDefaultMethods() && !iface->IsInitialized()) {
- TryInitializeClass(iface, class_loader);
+ TryInitializeClass(self, iface, class_loader);
if (!iface->IsInitialized()) {
return false;
}
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index ec5f757..2c040ab 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1865,7 +1865,8 @@
Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args ATTRIBUTE_UNUSED, JValue* result) {
ScopedObjectAccessUnchecked soa(self);
- result->SetL(soa.Decode<mirror::Object>(self->CreateInternalStackTrace(soa)));
+ ScopedLocalRef<jobject> stack_trace(self->GetJniEnv(), self->CreateInternalStackTrace(soa));
+ result->SetL(soa.Decode<mirror::Object>(stack_trace.get()));
}
void UnstartedRuntime::UnstartedJNIUnsafeCompareAndSwapInt(