summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/common_runtime_test.h1
-rw-r--r--runtime/interpreter/interpreter.cc1
-rw-r--r--runtime/interpreter/interpreter_common.cc78
-rw-r--r--runtime/interpreter/interpreter_goto_table_impl.cc1
-rw-r--r--runtime/interpreter/interpreter_switch_impl.cc1
-rw-r--r--runtime/mirror/class-inl.h8
-rw-r--r--runtime/mirror/class.h4
-rw-r--r--runtime/oat.cc2
-rw-r--r--runtime/reflection_test.cc11
9 files changed, 79 insertions, 28 deletions
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 289dc1de4..ac6d44b95 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -206,6 +206,7 @@ class CommonRuntimeTest : public testing::Test {
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 729444e4f..2db62f8ea 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -356,6 +356,7 @@ static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::Code
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 9f04b90c5..5a03601bc 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -35,6 +35,7 @@ bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst
CHECK(self->IsExceptionPending());
return false;
}
+ f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
Object* obj;
if (is_static) {
obj = f->GetDeclaringClass();
@@ -210,6 +211,7 @@ bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction
CHECK(self->IsExceptionPending());
return false;
}
+ f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
Object* obj;
if (is_static) {
obj = f->GetDeclaringClass();
@@ -757,40 +759,64 @@ void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
}
}
+// 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 cb4868c95..abd4b44d3 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -536,6 +536,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
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 bdf2a2019..c6356485a 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -449,6 +449,7 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem
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 451235c32..2daa6e49a 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -546,6 +546,14 @@ inline bool Class::DescriptorEquals(const char* match) {
}
}
+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 e735c4539..7ac53ea5f 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -880,6 +880,10 @@ class MANAGED Class : public Object {
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 857c0a24e..7c8e5bc36 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 3b66abee2..abe68ef8d 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -109,7 +109,16 @@ class ReflectionTest : public CommonCompilerTest {
: 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();