summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc245
1 files changed, 171 insertions, 74 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cf3a581668..f6717fb006 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -17,6 +17,7 @@
#include "class_linker.h"
#include <deque>
+#include <iostream>
#include <memory>
#include <queue>
#include <string>
@@ -32,6 +33,7 @@
#include "compiler_callbacks.h"
#include "debugger.h"
#include "dex_file-inl.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc_root-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/heap_bitmap.h"
@@ -115,7 +117,17 @@ static void ThrowEarlierClassFailure(mirror::Class* c)
}
}
-static void WrapExceptionInInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static void VlogClassInitializationFailure(Handle<mirror::Class> klass)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (VLOG_IS_ON(class_linker)) {
+ std::string temp;
+ LOG(INFO) << "Failed to initialize class " << klass->GetDescriptor(&temp) << " from "
+ << klass->GetLocation() << "\n" << Thread::Current()->GetException(nullptr)->Dump();
+ }
+}
+
+static void WrapExceptionInInitializer(Handle<mirror::Class> klass)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Thread* self = Thread::Current();
JNIEnv* env = self->GetJniEnv();
@@ -132,6 +144,7 @@ static void WrapExceptionInInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lo
self->ThrowNewWrappedException(throw_location, "Ljava/lang/ExceptionInInitializerError;",
nullptr);
}
+ VlogClassInitializationFailure(klass);
}
static size_t Hash(const char* s) {
@@ -225,44 +238,6 @@ static void ShuffleForward(const size_t num_fields, size_t* current_field_idx,
}
}
-const char* ClassLinker::class_roots_descriptors_[] = {
- "Ljava/lang/Class;",
- "Ljava/lang/Object;",
- "[Ljava/lang/Class;",
- "[Ljava/lang/Object;",
- "Ljava/lang/String;",
- "Ljava/lang/DexCache;",
- "Ljava/lang/ref/Reference;",
- "Ljava/lang/reflect/ArtField;",
- "Ljava/lang/reflect/ArtMethod;",
- "Ljava/lang/reflect/Proxy;",
- "[Ljava/lang/String;",
- "[Ljava/lang/reflect/ArtField;",
- "[Ljava/lang/reflect/ArtMethod;",
- "Ljava/lang/ClassLoader;",
- "Ljava/lang/Throwable;",
- "Ljava/lang/ClassNotFoundException;",
- "Ljava/lang/StackTraceElement;",
- "Z",
- "B",
- "C",
- "D",
- "F",
- "I",
- "J",
- "S",
- "V",
- "[Z",
- "[B",
- "[C",
- "[D",
- "[F",
- "[I",
- "[J",
- "[S",
- "[Ljava/lang/StackTraceElement;",
-};
-
ClassLinker::ClassLinker(InternTable* intern_table)
// dex_lock_ is recursive as it may be used in stack dumping.
: dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
@@ -281,16 +256,9 @@ ClassLinker::ClassLinker(InternTable* intern_table)
quick_imt_conflict_trampoline_(nullptr),
quick_generic_jni_trampoline_(nullptr),
quick_to_interpreter_bridge_trampoline_(nullptr) {
- CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
memset(find_array_class_cache_, 0, kFindArrayCacheSize * sizeof(mirror::Class*));
}
-// To set a value for generic JNI. May be necessary in compiler tests.
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-
void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class_path) {
VLOG(startup) << "ClassLinker::Init";
CHECK(!Runtime::Current()->GetHeap()->HasImageSpace()) << "Runtime has image. We should use it.";
@@ -471,12 +439,12 @@ void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class
// Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
// we do not need friend classes or a publicly exposed setter.
- quick_generic_jni_trampoline_ = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+ quick_generic_jni_trampoline_ = GetQuickGenericJniStub();
if (!runtime->IsCompiler()) {
// We need to set up the generic trampolines since we don't have an image.
- quick_resolution_trampoline_ = reinterpret_cast<void*>(art_quick_resolution_trampoline);
- quick_imt_conflict_trampoline_ = reinterpret_cast<void*>(art_quick_imt_conflict_trampoline);
- quick_to_interpreter_bridge_trampoline_ = reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
+ quick_resolution_trampoline_ = GetQuickResolutionStub();
+ quick_imt_conflict_trampoline_ = GetQuickImtConflictStub();
+ quick_to_interpreter_bridge_trampoline_ = GetQuickToInterpreterBridge();
}
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
@@ -560,15 +528,15 @@ void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class
CHECK_EQ(java_lang_reflect_ArtField.Get(), Art_field_class);
mirror::Class* String_array_class =
- FindSystemClass(self, class_roots_descriptors_[kJavaLangStringArrayClass]);
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass));
CHECK_EQ(object_array_string.Get(), String_array_class);
mirror::Class* Art_method_array_class =
- FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]);
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass));
CHECK_EQ(object_array_art_method.Get(), Art_method_array_class);
mirror::Class* Art_field_array_class =
- FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]);
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtFieldArrayClass));
CHECK_EQ(object_array_art_field.Get(), Art_field_array_class);
// End of special init trickery, subsequent classes may be loaded via FindSystemClass.
@@ -1655,7 +1623,7 @@ static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
if (obj->IsArtMethod()) {
mirror::ArtMethod* method = obj->AsArtMethod();
if (!method->IsNative()) {
- method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
if (method != Runtime::Current()->GetResolutionMethod()) {
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
@@ -2524,7 +2492,7 @@ const void* ClassLinker::GetQuickOatCodeFor(mirror::ArtMethod* method) {
if (result == nullptr) {
if (method->IsNative()) {
// No code and native? Use generic trampoline.
- result = GetQuickGenericJniTrampoline();
+ result = GetQuickGenericJniStub();
} else if (method->IsPortableCompiled()) {
// No code? Do we expect portable code?
result = GetQuickToPortableBridge();
@@ -2678,7 +2646,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
// Use interpreter entry point.
// Check whether the method is native, in which case it's generic JNI.
if (quick_code == nullptr && portable_code == nullptr && method->IsNative()) {
- quick_code = GetQuickGenericJniTrampoline();
+ quick_code = GetQuickGenericJniStub();
portable_code = GetPortableToQuickBridge();
} else {
portable_code = GetPortableToInterpreterBridge();
@@ -2704,7 +2672,8 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
const OatFile::OatClass* oat_class,
const DexFile& dex_file, uint32_t dex_method_index,
uint32_t method_index) {
- if (Runtime::Current()->IsCompiler()) {
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsCompiler()) {
// The following code only applies to a non-compiler runtime.
return;
}
@@ -2723,7 +2692,7 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
method->GetEntryPointFromQuickCompiledCode(),
method->GetEntryPointFromPortableCompiledCode());
if (enter_interpreter && !method->IsNative()) {
- method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
} else {
method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
}
@@ -2739,15 +2708,15 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
// For static methods excluding the class initializer, install the trampoline.
// It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines
// after initializing class (see ClassLinker::InitializeClass method).
- method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline());
- method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
+ method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionStub());
} else if (enter_interpreter) {
if (!method->IsNative()) {
// Set entry point from compiled code if there's no code or in interpreter only mode.
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
} else {
- method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniTrampoline());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
}
} else if (method->GetEntryPointFromPortableCompiledCode() != nullptr) {
@@ -2761,18 +2730,18 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
if (method->IsNative()) {
// Unregistering restores the dlsym lookup stub.
- method->UnregisterNative(Thread::Current());
+ method->UnregisterNative();
if (enter_interpreter) {
- // We have a native method here without code. Then it should have either the GenericJni
- // trampoline as entrypoint (non-static), or the Resolution trampoline (static).
- DCHECK(method->GetEntryPointFromQuickCompiledCode() == GetQuickResolutionTrampoline()
- || method->GetEntryPointFromQuickCompiledCode() == GetQuickGenericJniTrampoline());
+ // We have a native method here without code. Then it should have either the generic JNI
+ // trampoline as entrypoint (non-static), or the resolution trampoline (static).
+ // TODO: this doesn't handle all the cases where trampolines may be installed.
+ const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
+ DCHECK(IsQuickGenericJniStub(entry_point) || IsQuickResolutionStub(entry_point));
}
}
// Allow instrumentation its chance to hijack code.
- Runtime* runtime = Runtime::Current();
runtime->GetInstrumentation()->UpdateMethodsCode(method.Get(),
method->GetEntryPointFromQuickCompiledCode(),
method->GetEntryPointFromPortableCompiledCode(),
@@ -3213,13 +3182,13 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto
new_class.Assign(GetClassRoot(kClassArrayClass));
} else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
new_class.Assign(GetClassRoot(kObjectArrayClass));
- } else if (strcmp(descriptor, class_roots_descriptors_[kJavaLangStringArrayClass]) == 0) {
+ } else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) {
new_class.Assign(GetClassRoot(kJavaLangStringArrayClass));
} else if (strcmp(descriptor,
- class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) == 0) {
+ GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass)) == 0) {
new_class.Assign(GetClassRoot(kJavaLangReflectArtMethodArrayClass));
} else if (strcmp(descriptor,
- class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) == 0) {
+ GetClassRootDescriptor(kJavaLangReflectArtFieldArrayClass)) == 0) {
new_class.Assign(GetClassRoot(kJavaLangReflectArtFieldArrayClass));
} else if (strcmp(descriptor, "[C") == 0) {
new_class.Assign(GetClassRoot(kCharArrayClass));
@@ -4151,6 +4120,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// Was the class already found to be erroneous? Done under the lock to match the JLS.
if (klass->IsErroneous()) {
ThrowEarlierClassFailure(klass.Get());
+ VlogClassInitializationFailure(klass);
return false;
}
@@ -4163,6 +4133,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// compile time.
if (klass->IsErroneous()) {
CHECK(self->IsExceptionPending());
+ VlogClassInitializationFailure(klass);
} else {
CHECK(Runtime::Current()->IsCompiler());
CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
@@ -4181,6 +4152,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
// Could have got an exception during verification.
if (self->IsExceptionPending()) {
+ VlogClassInitializationFailure(klass);
return false;
}
// We caught somebody else in the act; was it us?
@@ -4277,7 +4249,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
ObjectLock<mirror::Class> lock(self, klass);
if (self->IsExceptionPending()) {
- WrapExceptionInInitializer();
+ WrapExceptionInInitializer(klass);
klass->SetStatus(mirror::Class::kStatusError, self);
success = false;
} else {
@@ -4311,9 +4283,9 @@ bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, Thread* se
// When we wake up, repeat the test for init-in-progress. If
// there's an exception pending (only possible if
- // "interruptShouldThrow" was set), bail out.
+ // we were not using WaitIgnoringInterrupts), bail out.
if (self->IsExceptionPending()) {
- WrapExceptionInInitializer();
+ WrapExceptionInInitializer(klass);
klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
@@ -4330,6 +4302,7 @@ bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, Thread* se
// different thread. Synthesize one here.
ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread",
PrettyDescriptor(klass.Get()).c_str());
+ VlogClassInitializationFailure(klass);
return false;
}
if (klass->IsInitialized()) {
@@ -5138,7 +5111,7 @@ bool ClassLinker::LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_
bool seen_non_ref = false;
for (size_t i = 0; i < num_fields; i++) {
mirror::ArtField* field = fields->Get(i);
- if (false) { // enable to debug field layout
+ if ((false)) { // enable to debug field layout
LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance")
<< " class=" << PrettyClass(klass.Get())
<< " field=" << PrettyField(field)
@@ -5531,6 +5504,84 @@ void ClassLinker::DumpAllClasses(int flags) {
}
}
+static OatFile::OatMethod CreateOatMethod(const void* code, const uint8_t* gc_map,
+ bool is_portable) {
+ CHECK_EQ(kUsePortableCompiler, is_portable);
+ CHECK(code != nullptr);
+ const uint8_t* base;
+ uint32_t code_offset, gc_map_offset;
+ if (gc_map == nullptr) {
+ base = reinterpret_cast<const uint8_t*>(code); // Base of data points at code.
+ base -= sizeof(void*); // Move backward so that code_offset != 0.
+ code_offset = sizeof(void*);
+ gc_map_offset = 0;
+ } else {
+ // TODO: 64bit support.
+ base = nullptr; // Base of data in oat file, ie 0.
+ code_offset = PointerToLowMemUInt32(code);
+ gc_map_offset = PointerToLowMemUInt32(gc_map);
+ }
+ return OatFile::OatMethod(base, code_offset, gc_map_offset);
+}
+
+bool ClassLinker::IsPortableResolutionStub(const void* entry_point) const {
+ return (entry_point == GetPortableResolutionStub()) ||
+ (portable_resolution_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const {
+ return (entry_point == GetQuickResolutionStub()) ||
+ (quick_resolution_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsPortableToInterpreterBridge(const void* entry_point) const {
+ return (entry_point == GetPortableToInterpreterBridge());
+ // TODO: portable_to_interpreter_bridge_trampoline_ == entry_point;
+}
+
+bool ClassLinker::IsQuickToInterpreterBridge(const void* entry_point) const {
+ return (entry_point == GetQuickToInterpreterBridge()) ||
+ (quick_to_interpreter_bridge_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsQuickGenericJniStub(const void* entry_point) const {
+ return (entry_point == GetQuickGenericJniStub()) ||
+ (quick_generic_jni_trampoline_ == entry_point);
+}
+
+const void* ClassLinker::GetRuntimeQuickGenericJniStub() const {
+ return GetQuickGenericJniStub();
+}
+
+void ClassLinker::SetEntryPointsToCompiledCode(mirror::ArtMethod* method, const void* method_code,
+ bool is_portable) const {
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr, is_portable);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+ // Create bridges to transition between different kinds of compiled bridge.
+ if (method->GetEntryPointFromPortableCompiledCode() == nullptr) {
+ method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+ } else {
+ CHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
+ method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge());
+ method->SetIsPortableCompiled();
+ }
+}
+
+void ClassLinker::SetEntryPointsToInterpreter(mirror::ArtMethod* method) const {
+ if (!method->IsNative()) {
+ method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
+ method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
+ } else {
+ const void* quick_method_code = GetQuickGenericJniStub();
+ OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code, nullptr, false);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+ method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+ }
+}
+
void ClassLinker::DumpForSigQuit(std::ostream& os) {
Thread* self = Thread::Current();
if (dex_cache_image_class_lookup_required_) {
@@ -5569,4 +5620,50 @@ void ClassLinker::SetClassRoot(ClassRoot class_root, mirror::Class* klass) {
class_roots->Set<false>(class_root, klass);
}
+const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) {
+ static const char* class_roots_descriptors[] = {
+ "Ljava/lang/Class;",
+ "Ljava/lang/Object;",
+ "[Ljava/lang/Class;",
+ "[Ljava/lang/Object;",
+ "Ljava/lang/String;",
+ "Ljava/lang/DexCache;",
+ "Ljava/lang/ref/Reference;",
+ "Ljava/lang/reflect/ArtField;",
+ "Ljava/lang/reflect/ArtMethod;",
+ "Ljava/lang/reflect/Proxy;",
+ "[Ljava/lang/String;",
+ "[Ljava/lang/reflect/ArtField;",
+ "[Ljava/lang/reflect/ArtMethod;",
+ "Ljava/lang/ClassLoader;",
+ "Ljava/lang/Throwable;",
+ "Ljava/lang/ClassNotFoundException;",
+ "Ljava/lang/StackTraceElement;",
+ "Z",
+ "B",
+ "C",
+ "D",
+ "F",
+ "I",
+ "J",
+ "S",
+ "V",
+ "[Z",
+ "[B",
+ "[C",
+ "[D",
+ "[F",
+ "[I",
+ "[J",
+ "[S",
+ "[Ljava/lang/StackTraceElement;",
+ };
+ COMPILE_ASSERT(arraysize(class_roots_descriptors) == size_t(kClassRootsMax),
+ mismatch_between_class_descriptors_and_class_root_enum);
+
+ const char* descriptor = class_roots_descriptors[class_root];
+ CHECK(descriptor != nullptr);
+ return descriptor;
+}
+
} // namespace art