Make ART compile with GCC -O0 again.
Tidy up InstructionSetFeatures so that it has a type hierarchy dependent on
architecture.
Add to instruction_set_test to warn when InstructionSetFeatures don't agree
with ones from system properties, AT_HWCAP and /proc/cpuinfo.
Clean-up class linker entry point logic to not return entry points but to
test whether the passed code is the particular entrypoint. This works around
image trampolines that replicate entrypoints.
Bug: 17993736
Change-Id: I5f4b49e88c3b02a79f9bee04f83395146ed7be23
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5718e44..bbbb9e0 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -32,6 +32,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"
@@ -236,44 +237,6 @@
}
}
-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),
@@ -292,16 +255,9 @@
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.";
@@ -482,12 +438,12 @@
// 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
@@ -571,15 +527,15 @@
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.
@@ -1666,7 +1622,7 @@
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());
@@ -2535,7 +2491,7 @@
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();
@@ -2689,7 +2645,7 @@
// 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();
@@ -2715,7 +2671,8 @@
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;
}
@@ -2734,7 +2691,7 @@
method->GetEntryPointFromQuickCompiledCode(),
method->GetEntryPointFromPortableCompiledCode());
if (enter_interpreter && !method->IsNative()) {
- method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+ method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
} else {
method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
}
@@ -2750,15 +2707,15 @@
// 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) {
@@ -2772,18 +2729,18 @@
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(),
@@ -3224,13 +3181,13 @@
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));
@@ -5546,6 +5503,84 @@
}
}
+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_) {
@@ -5584,4 +5619,50 @@
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