Merge "Add missing class initialization during compilation and tests"
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 80e7724..72c34b4 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -467,6 +467,7 @@
}
}
runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod());
+ runtime->GetClassLinker()->RunRootClinits();
runtime_ = runtime;
return true;
}
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 289dc1d..ac6d44b 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -206,6 +206,7 @@
runtime_.reset(Runtime::Current());
class_linker_ = runtime_->GetClassLinker();
class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+ class_linker_->RunRootClinits();
// Runtime::Create acquired the mutator_lock_ that is normally given away when we
// Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 729444e..2db62f8 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -356,6 +356,7 @@
shadow_frame.GetMethod()->GetDeclaringClass()->IsProxyClass());
DCHECK(!shadow_frame.GetMethod()->IsAbstract());
DCHECK(!shadow_frame.GetMethod()->IsNative());
+ shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
bool transaction_active = Runtime::Current()->IsActiveTransaction();
if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 9f04b90..5a03601 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -35,6 +35,7 @@
CHECK(self->IsExceptionPending());
return false;
}
+ f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
Object* obj;
if (is_static) {
obj = f->GetDeclaringClass();
@@ -210,6 +211,7 @@
CHECK(self->IsExceptionPending());
return false;
}
+ f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
Object* obj;
if (is_static) {
obj = f->GetDeclaringClass();
@@ -757,40 +759,64 @@
}
}
+// Helper function to deal with class loading in an unstarted runtime.
+static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> className,
+ Handle<mirror::ClassLoader> class_loader, JValue* result,
+ const std::string& method_name, bool initialize_class,
+ bool abort_if_not_found)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CHECK(className.Get() != nullptr);
+ std::string descriptor(DotToDescriptor(className->ToModifiedUtf8().c_str()));
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+ Class* found = class_linker->FindClass(self, descriptor.c_str(), class_loader);
+ if (found == nullptr && abort_if_not_found) {
+ if (!self->IsExceptionPending()) {
+ AbortTransaction(self, "%s failed in un-started runtime for class: %s",
+ method_name.c_str(), PrettyDescriptor(descriptor).c_str());
+ }
+ return;
+ }
+ if (found != nullptr && initialize_class) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> h_class(hs.NewHandle(found));
+ if (!class_linker->EnsureInitialized(h_class, true, true)) {
+ CHECK(self->IsExceptionPending());
+ return;
+ }
+ }
+ result->SetL(found);
+}
+
static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
JValue* result, size_t arg_offset) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
std::string name(PrettyMethod(shadow_frame->GetMethod()));
- if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)"
- || name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
- // TODO Class#forName should actually call Class::EnsureInitialized always. Support for the
- // other variants that take more arguments should also be added.
- std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
-
- // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
- Class* found = Runtime::Current()->GetClassLinker()->FindClass(
- self, descriptor.c_str(), NullHandle<mirror::ClassLoader>());
- if (found == NULL) {
- if (!self->IsExceptionPending()) {
- AbortTransaction(self, "Class.forName failed in un-started runtime for class: %s",
- PrettyDescriptor(descriptor).c_str());
- }
- return;
- }
- result->SetL(found);
+ if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
+ // TODO: Support for the other variants that take more arguments should also be added.
+ mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+ UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
+ true, true);
+ } else if (name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
+ mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+ UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
+ false, true);
+ } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
+ mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
+ mirror::ClassLoader* class_loader =
+ down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset));
+ StackHandleScope<2> hs(self);
+ Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+ Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
+ UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, name, false, false);
} else if (name == "java.lang.Class java.lang.Void.lookupType()") {
result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
- } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
- StackHandleScope<1> hs(self);
- Handle<ClassLoader> class_loader(
- hs.NewHandle(down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset))));
- std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
-
- Class* found = Runtime::Current()->GetClassLinker()->FindClass(self, descriptor.c_str(),
- class_loader);
- result->SetL(found);
} else if (name == "java.lang.Object java.lang.Class.newInstance()") {
Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index cb4868c..abd4b44 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -536,6 +536,7 @@
if (UNLIKELY(obj == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
+ obj->GetClass()->AssertInitializedOrInitializingInThread(self);
// Don't allow finalizable objects to be allocated during a transaction since these can't be
// finalized without a started runtime.
if (transaction_active && obj->GetClass()->IsFinalizable()) {
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index bdf2a20..c635648 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -449,6 +449,7 @@
if (UNLIKELY(obj == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
+ obj->GetClass()->AssertInitializedOrInitializingInThread(self);
// Don't allow finalizable objects to be allocated during a transaction since these can't
// be finalized without a started runtime.
if (transaction_active && obj->GetClass()->IsFinalizable()) {
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 451235c..2daa6e4 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -546,6 +546,14 @@
}
}
+inline void Class::AssertInitializedOrInitializingInThread(Thread* self) {
+ if (kIsDebugBuild && !IsInitialized()) {
+ CHECK(IsInitializing()) << PrettyClass(this) << " is not initializing: " << GetStatus();
+ CHECK_EQ(GetClinitThreadId(), self->GetTid()) << PrettyClass(this)
+ << " is initializing in a different thread";
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index e735c45..7ac53ea 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -880,6 +880,10 @@
const DexFile& GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const DexFile::TypeList* GetInterfaceTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Asserts we are initialized or initializing in the given thread.
+ void AssertInitializedOrInitializingInThread(Thread* self)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 857c0a2..7c8e5bc 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '3', '6', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '3', '7', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 3b66abe..abe68ef 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -109,7 +109,16 @@
: c->FindVirtualMethod(method_name, method_signature);
CHECK(method != nullptr);
- *receiver = (is_static ? nullptr : c->AllocObject(self));
+ if (is_static) {
+ *receiver = nullptr;
+ } else {
+ // Ensure class is initialized before allocating object
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> h_class(hs.NewHandle(c));
+ bool initialized = class_linker_->EnsureInitialized(h_class, true, true);
+ CHECK(initialized);
+ *receiver = c->AllocObject(self);
+ }
// Start runtime.
bool started = runtime_->Start();