summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorJeff Hao <jeffhao@google.com>2013-10-23 16:24:40 -0700
committerJeff Hao <jeffhao@google.com>2013-10-29 12:01:28 -0700
commit88474b416eb257078e590bf9bc7957cee604a186 (patch)
tree7c59aa370bec9b0f2d37cb7a96d3b2effb3d92ce /runtime
parent9780099e445884d8bc9444c8c1261b02d80a26c7 (diff)
downloadart-88474b416eb257078e590bf9bc7957cee604a186.zip
art-88474b416eb257078e590bf9bc7957cee604a186.tar.gz
art-88474b416eb257078e590bf9bc7957cee604a186.tar.bz2
Implement Interface Method Tables (IMT).
Change-Id: Idf7fe85e1293453a8ad862ff2380dcd5db4e3a39
Diffstat (limited to 'runtime')
-rw-r--r--runtime/arch/arm/entrypoints_init_arm.cc4
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S12
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc4
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S15
-rw-r--r--runtime/arch/x86/entrypoints_init_x86.cc4
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S14
-rw-r--r--runtime/asm_support.h3
-rw-r--r--runtime/class_linker.cc39
-rw-r--r--runtime/class_linker.h19
-rw-r--r--runtime/class_linker_test.cc7
-rw-r--r--runtime/common_test.h3
-rw-r--r--runtime/entrypoints/entrypoint_utils.h38
-rw-r--r--runtime/entrypoints/portable/portable_entrypoints.h1
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints.h2
-rw-r--r--runtime/gc/space/image_space.cc4
-rw-r--r--runtime/image.h2
-rw-r--r--runtime/mirror/art_method-inl.h7
-rw-r--r--runtime/mirror/art_method.h2
-rw-r--r--runtime/mirror/class-inl.h8
-rw-r--r--runtime/mirror/class.h13
-rw-r--r--runtime/mirror/object_test.cc1
-rw-r--r--runtime/mirror/string.h2
-rw-r--r--runtime/oat.cc50
-rw-r--r--runtime/oat.h8
-rw-r--r--runtime/object_utils.h2
-rw-r--r--runtime/runtime.cc31
-rw-r--r--runtime/runtime.h38
-rw-r--r--runtime/thread.cc3
28 files changed, 307 insertions, 29 deletions
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 352982f..3dac636 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -121,10 +121,10 @@ extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
extern "C" int32_t art_quick_string_compareto(void*, void*);
// Invoke entrypoints.
+extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
@@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pMemcpy = memcpy;
// Invocation
+ qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline;
qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline;
qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge;
qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
- qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check;
qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check;
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 736ce2f..808ff5b 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1040,6 +1040,18 @@ ENTRY art_quick_proxy_invoke_handler
DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler
+ /*
+ * Called to resolve an imt conflict. r12 is a hidden argument that holds the target method's
+ * dex method index.
+ */
+ENTRY art_quick_imt_conflict_trampoline
+ ldr r0, [sp, #0] @ load caller Method*
+ ldr r0, [r0, #METHOD_DEX_CACHE_METHODS_OFFSET] @ load dex_cache_resolved_methods
+ add r0, #OBJECT_ARRAY_DATA_OFFSET @ get starting address of data
+ ldr r0, [r0, r12, lsl 2] @ load the target method
+ b art_quick_invoke_interface_trampoline
+END art_quick_imt_conflict_trampoline
+
.extern artQuickResolutionTrampoline
ENTRY art_quick_resolution_trampoline
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index cc975d75..331a461 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -122,10 +122,10 @@ extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
extern "C" int32_t art_quick_string_compareto(void*, void*);
// Invoke entrypoints.
+extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
@@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pMemcpy = memcpy;
// Invocation
+ qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline;
qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline;
qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge;
qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
- qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check;
qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check;
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 031d13a..451b1bb 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -1060,6 +1060,21 @@ ENTRY art_quick_proxy_invoke_handler
DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler
+ /*
+ * Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's
+ * dex method index.
+ */
+ENTRY art_quick_imt_conflict_trampoline
+ GENERATE_GLOBAL_POINTER
+ lw $a0, 0($sp) # load caller Method*
+ lw $a0, METHOD_DEX_CACHE_METHODS_OFFSET($a0) # load dex_cache_resolved_methods
+ sll $t0, 2 # convert target method offset to bytes
+ add $a0, $t0 # get address of target method
+ lw $a0, OBJECT_ARRAY_DATA_OFFSET($a0) # load the target method
+ la $t9, art_quick_invoke_interface_trampoline
+ jr $t9
+END art_quick_imt_conflict_trampoline
+
.extern artQuickResolutionTrampoline
ENTRY art_quick_resolution_trampoline
GENERATE_GLOBAL_POINTER
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 89dd1b8..99b0dd5 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -104,10 +104,10 @@ extern "C" int32_t art_quick_string_compareto(void*, void*);
extern "C" void* art_quick_memcpy(void*, const void*, size_t);
// Invoke entrypoints.
+extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
@@ -235,10 +235,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pMemcpy = art_quick_memcpy;
// Invocation
+ qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline;
qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline;
qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge;
qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
- qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check;
qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check;
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 805f6f4..6a6891b 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -997,6 +997,20 @@ DEFINE_FUNCTION art_quick_proxy_invoke_handler
RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
END_FUNCTION art_quick_proxy_invoke_handler
+ /*
+ * Called to resolve an imt conflict. xmm0 is a hidden argument that holds the target method's
+ * dex method index.
+ */
+DEFINE_FUNCTION art_quick_imt_conflict_trampoline
+ PUSH ecx
+ movl 8(%esp), %eax // load caller Method*
+ movl METHOD_DEX_CACHE_METHODS_OFFSET(%eax), %eax // load dex_cache_resolved_methods
+ movd %xmm0, %ecx // get target method index stored in xmm0
+ movl OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax // load the target method
+ POP ecx
+ jmp art_quick_invoke_interface_trampoline
+END_FUNCTION art_quick_imt_conflict_trampoline
+
DEFINE_FUNCTION art_quick_resolution_trampoline
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
PUSH esp // pass SP
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index a6700bc..e9bbf91 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -38,7 +38,8 @@
#define STRING_OFFSET_OFFSET 20
#define STRING_DATA_OFFSET 12
-// Offset of field Method::entry_point_from_compiled_code_
+// Offsets within java.lang.Method.
+#define METHOD_DEX_CACHE_METHODS_OFFSET 16
#define METHOD_CODE_OFFSET 40
#endif // ART_RUNTIME_ASM_SUPPORT_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 03f2c9d..2fc564f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -196,7 +196,9 @@ ClassLinker::ClassLinker(InternTable* intern_table)
class_table_dirty_(false),
intern_table_(intern_table),
portable_resolution_trampoline_(NULL),
- quick_resolution_trampoline_(NULL) {
+ quick_resolution_trampoline_(NULL),
+ portable_imt_conflict_trampoline_(NULL),
+ quick_imt_conflict_trampoline_(NULL) {
CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
}
@@ -336,6 +338,12 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
InitializePrimitiveClass(char_class.get(), Primitive::kPrimChar);
SetClassRoot(kPrimitiveChar, char_class.get()); // needs descriptor
+ // Create runtime resolution and imt conflict methods. Also setup the default imt.
+ Runtime* runtime = Runtime::Current();
+ runtime->SetResolutionMethod(runtime->CreateResolutionMethod());
+ runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod());
+ runtime->SetDefaultImt(runtime->CreateDefaultImt(this));
+
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Object_class = FindSystemClass("Ljava/lang/Object;");
@@ -1045,6 +1053,8 @@ void ClassLinker::InitFromImage() {
CHECK(oat_file.GetOatHeader().GetImageFileLocation().empty());
portable_resolution_trampoline_ = oat_file.GetOatHeader().GetPortableResolutionTrampoline();
quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline();
+ portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline();
+ quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline();
mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
mirror::ObjectArray<mirror::DexCache>* dex_caches =
dex_caches_object->AsObjectArray<mirror::DexCache>();
@@ -3518,6 +3528,8 @@ bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) {
bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
mirror::ObjectArray<mirror::Class>* interfaces) {
+ // Set the imt table to be all conflicts by default.
+ klass->SetImTable(Runtime::Current()->GetDefaultImt());
size_t super_ifcount;
if (klass->HasSuperClass()) {
super_ifcount = klass->GetSuperClass()->GetIfTableCount();
@@ -3625,6 +3637,13 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
if (klass->IsInterface()) {
return true;
}
+ // Allocate imtable
+ bool imtable_changed = false;
+ SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, AllocArtMethodArray(self, kImtSize));
+ if (UNLIKELY(imtable.get() == NULL)) {
+ CHECK(self->IsExceptionPending()); // OOME.
+ return false;
+ }
std::vector<mirror::ArtMethod*> miranda_list;
MethodHelper vtable_mh(NULL, this);
MethodHelper interface_mh(NULL, this);
@@ -3664,6 +3683,14 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
return false;
}
method_array->Set(j, vtable_method);
+ // Place method in imt if entry is empty, place conflict otherwise.
+ uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize;
+ if (imtable->Get(imt_index) == NULL) {
+ imtable->Set(imt_index, vtable_method);
+ imtable_changed = true;
+ } else {
+ imtable->Set(imt_index, Runtime::Current()->GetImtConflictMethod());
+ }
break;
}
}
@@ -3695,6 +3722,16 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
}
}
}
+ if (imtable_changed) {
+ // Fill in empty entries in interface method table with conflict.
+ mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
+ for (size_t i = 0; i < kImtSize; i++) {
+ if (imtable->Get(i) == NULL) {
+ imtable->Set(i, imt_conflict_method);
+ }
+ }
+ klass->SetImTable(imtable.get());
+ }
if (!miranda_list.empty()) {
int old_method_count = klass->NumVirtualMethods();
int new_method_count = old_method_count + miranda_list.size();
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 0bc1b5f..473370d 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -51,6 +51,11 @@ typedef bool (ClassVisitor)(mirror::Class* c, void* arg);
class ClassLinker {
public:
+ // Interface method table size. Increasing this value reduces the chance of two interface methods
+ // colliding in the interface method table but increases the size of classes that implement
+ // (non-marker) interfaces.
+ static constexpr size_t kImtSize = 64;
+
// Creates the class linker by bootstrapping from dex files.
static ClassLinker* CreateFromCompiler(const std::vector<const DexFile*>& boot_class_path,
InternTable* intern_table)
@@ -340,6 +345,18 @@ class ClassLinker {
return quick_resolution_trampoline_;
}
+ const void* GetPortableImtConflictTrampoline() const {
+ return portable_imt_conflict_trampoline_;
+ }
+
+ const void* GetQuickImtConflictTrampoline() const {
+ return quick_imt_conflict_trampoline_;
+ }
+
+ InternTable* GetInternTable() const {
+ return intern_table_;
+ }
+
// Attempts to insert a class into a class table. Returns NULL if
// the class was inserted, otherwise returns an existing class with
// the same descriptor and ClassLoader.
@@ -608,6 +625,8 @@ class ClassLinker {
const void* portable_resolution_trampoline_;
const void* quick_resolution_trampoline_;
+ const void* portable_imt_conflict_trampoline_;
+ const void* quick_imt_conflict_trampoline_;
friend class ImageWriter; // for GetClassRoots
FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 029b73e..a52b680 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -497,6 +497,7 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> {
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, imtable_), "imTable"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass"));
@@ -582,11 +583,11 @@ struct StringClassOffsets : public CheckOffsets<mirror::StringClass> {
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_), "ASCII"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER"));
- // alphabetical 64-bit
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID"));
-
// alphabetical 32-bit
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR"));
+
+ // alphabetical 64-bit
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID"));
};
};
diff --git a/runtime/common_test.h b/runtime/common_test.h
index 899eab1..673a03b 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -329,9 +329,6 @@ class CommonTest : public testing::Test {
CompilerBackend compiler_backend = kQuick;
#endif
- if (!runtime_->HasResolutionMethod()) {
- runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod());
- }
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
if (!runtime_->HasCalleeSaveMethod(type)) {
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 2008604..7ce50c5 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -372,14 +372,21 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror:
return vtable->GetWithoutChecks(vtable_index);
}
case kInterface: {
- mirror::ArtMethod* interface_method =
- this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
- if (UNLIKELY(interface_method == nullptr)) {
- ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object,
- referrer);
- return nullptr; // Failure.
+ uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize;
+ mirror::ObjectArray<mirror::ArtMethod>* imt_table = this_object->GetClass()->GetImTable();
+ mirror::ArtMethod* imt_method = imt_table->Get(imt_index);
+ if (!imt_method->IsImtConflictMethod()) {
+ return imt_method;
} else {
- return interface_method;
+ mirror::ArtMethod* interface_method =
+ this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ if (UNLIKELY(interface_method == nullptr)) {
+ ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object,
+ referrer);
+ return nullptr; // Failure.
+ } else {
+ return interface_method;
+ }
}
}
default:
@@ -665,6 +672,23 @@ static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) {
#endif
}
+static inline const void* GetPortableImtConflictTrampoline(ClassLinker* class_linker) {
+ return class_linker->GetPortableImtConflictTrampoline();
+}
+
+static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linker) {
+ return class_linker->GetQuickImtConflictTrampoline();
+}
+
+// Return address of imt conflict trampoline stub for defined compiler.
+static inline const void* GetImtConflictTrampoline(ClassLinker* class_linker) {
+#if defined(ART_USE_PORTABLE_COMPILER)
+ return GetPortableImtConflictTrampoline(class_linker);
+#else
+ return GetQuickImtConflictTrampoline(class_linker);
+#endif
+}
+
extern "C" void art_portable_proxy_invoke_handler();
static inline const void* GetPortableProxyInvokeHandler() {
return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
diff --git a/runtime/entrypoints/portable/portable_entrypoints.h b/runtime/entrypoints/portable/portable_entrypoints.h
index d456447..dbea707 100644
--- a/runtime/entrypoints/portable/portable_entrypoints.h
+++ b/runtime/entrypoints/portable/portable_entrypoints.h
@@ -35,6 +35,7 @@ class Thread;
// compiler ABI.
struct PACKED(4) PortableEntryPoints {
// Invocation
+ void (*pPortableImtConflictTrampoline)(mirror::ArtMethod*);
void (*pPortableResolutionTrampoline)(mirror::ArtMethod*);
void (*pPortableToInterpreterBridge)(mirror::ArtMethod*);
};
diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h
index c8a85a0..1ba2066 100644
--- a/runtime/entrypoints/quick/quick_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_entrypoints.h
@@ -118,10 +118,10 @@ struct PACKED(4) QuickEntryPoints {
void* (*pMemcpy)(void*, const void*, size_t);
// Invocation
+ void (*pQuickImtConflictTrampoline)(mirror::ArtMethod*);
void (*pQuickResolutionTrampoline)(mirror::ArtMethod*);
void (*pQuickToInterpreterBridge)(mirror::ArtMethod*);
void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
- void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*);
void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*);
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index fa28642..e12ee06 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -241,6 +241,10 @@ ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file
Runtime* runtime = Runtime::Current();
mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
+ mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod);
+ runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method));
+ mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt);
+ runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
diff --git a/runtime/image.h b/runtime/image.h
index 2cb468f..246f106 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -90,6 +90,8 @@ class PACKED(4) ImageHeader {
enum ImageRoot {
kResolutionMethod,
+ kImtConflictMethod,
+ kDefaultImt,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index ccf3e59..c9bf160 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -202,6 +202,13 @@ inline bool ArtMethod::IsResolutionMethod() const {
DCHECK(!result || IsRuntimeMethod());
return result;
}
+
+inline bool ArtMethod::IsImtConflictMethod() const {
+ bool result = this == Runtime::Current()->GetImtConflictMethod();
+ // Check that if we do think it is phony it looks like the imt conflict method.
+ DCHECK(!result || IsRuntimeMethod());
+ return result;
+}
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 0520893..f396fbe 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -357,6 +357,8 @@ class MANAGED ArtMethod : public Object {
bool IsResolutionMethod() const;
+ bool IsImtConflictMethod() const;
+
uintptr_t NativePcOffset(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Converts a native PC to a dex PC.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index cd5e865..7f3a302 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -139,6 +139,14 @@ inline void Class::SetVTable(ObjectArray<ArtMethod>* new_vtable)
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false);
}
+inline ObjectArray<ArtMethod>* Class::GetImTable() const {
+ return GetFieldObject<ObjectArray<ArtMethod>*>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), false);
+}
+
+inline void Class::SetImTable(ObjectArray<ArtMethod>* new_imtable) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false);
+}
+
inline bool Class::Implements(const Class* klass) const {
DCHECK(klass != NULL);
DCHECK(klass->IsInterface()) << PrettyClass(this);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index d15f337..ed1aad3 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -555,6 +555,15 @@ class MANAGED Class : public StaticStorageBase {
return OFFSET_OF_OBJECT_MEMBER(Class, vtable_);
}
+ ObjectArray<ArtMethod>* GetImTable() const;
+
+ void SetImTable(ObjectArray<ArtMethod>* new_imtable)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static MemberOffset ImTableOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Class, imtable_);
+ }
+
// Given a method implemented by this class but potentially from a super class, return the
// specific implementation method for this class.
ArtMethod* FindVirtualMethodForVirtual(ArtMethod* method) const
@@ -830,6 +839,9 @@ class MANAGED Class : public StaticStorageBase {
// methods for the methods in the interface.
IfTable* iftable_;
+ // Interface method table (imt), for quick "invoke-interface".
+ ObjectArray<ArtMethod>* imtable_;
+
// descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
String* name_;
@@ -912,6 +924,7 @@ std::ostream& operator<<(std::ostream& os, const Class::Status& rhs);
class MANAGED ClassClass : public Class {
private:
+ int32_t pad_;
int64_t serialVersionUID_;
friend struct art::ClassClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass);
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 6c6d488..d0d1ee4 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -84,6 +84,7 @@ TEST_F(ObjectTest, AsmConstants) {
EXPECT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value());
EXPECT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value());
+ EXPECT_EQ(METHOD_DEX_CACHE_METHODS_OFFSET, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
EXPECT_EQ(METHOD_CODE_OFFSET, ArtMethod::EntryPointFromCompiledCodeOffset().Int32Value());
}
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 1879f04..01d8f31 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -156,8 +156,8 @@ class MANAGED StringClass : public Class {
private:
CharArray* ASCII_;
Object* CASE_INSENSITIVE_ORDER_;
- int64_t serialVersionUID_;
uint32_t REPLACEMENT_CHAR_;
+ int64_t serialVersionUID_;
friend struct art::StringClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass);
};
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 6fe5d10..defda6b 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', '0', '8', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '0', '9', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
@@ -60,8 +60,10 @@ OatHeader::OatHeader(InstructionSet instruction_set,
interpreter_to_interpreter_bridge_offset_ = 0;
interpreter_to_compiled_code_bridge_offset_ = 0;
jni_dlsym_lookup_offset_ = 0;
+ portable_imt_conflict_trampoline_offset_ = 0;
portable_resolution_trampoline_offset_ = 0;
portable_to_interpreter_bridge_offset_ = 0;
+ quick_imt_conflict_trampoline_offset_ = 0;
quick_resolution_trampoline_offset_ = 0;
quick_to_interpreter_bridge_offset_ = 0;
}
@@ -171,18 +173,37 @@ void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) {
UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset));
}
+const void* OatHeader::GetPortableImtConflictTrampoline() const {
+ return reinterpret_cast<const uint8_t*>(this) + GetPortableImtConflictTrampolineOffset();
+}
+
+uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const {
+ DCHECK(IsValid());
+ CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_);
+ return portable_imt_conflict_trampoline_offset_;
+}
+
+void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) {
+ CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
+ DCHECK(IsValid());
+ DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset;
+
+ portable_imt_conflict_trampoline_offset_ = offset;
+ UpdateChecksum(&portable_imt_conflict_trampoline_offset_, sizeof(offset));
+}
+
const void* OatHeader::GetPortableResolutionTrampoline() const {
return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
}
uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
DCHECK(IsValid());
- CHECK_GE(portable_resolution_trampoline_offset_, jni_dlsym_lookup_offset_);
+ CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_);
return portable_resolution_trampoline_offset_;
}
void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
- CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
+ CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_);
DCHECK(IsValid());
DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;
@@ -209,18 +230,37 @@ void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) {
UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset));
}
+const void* OatHeader::GetQuickImtConflictTrampoline() const {
+ return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset();
+}
+
+uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
+ DCHECK(IsValid());
+ CHECK_GE(quick_imt_conflict_trampoline_offset_, portable_to_interpreter_bridge_offset_);
+ return quick_imt_conflict_trampoline_offset_;
+}
+
+void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
+ CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
+ DCHECK(IsValid());
+ DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;
+
+ quick_imt_conflict_trampoline_offset_ = offset;
+ UpdateChecksum(&quick_imt_conflict_trampoline_offset_, sizeof(offset));
+}
+
const void* OatHeader::GetQuickResolutionTrampoline() const {
return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
}
uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
DCHECK(IsValid());
- CHECK_GE(quick_resolution_trampoline_offset_, portable_to_interpreter_bridge_offset_);
+ CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_);
return quick_resolution_trampoline_offset_;
}
void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
- CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
+ CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_);
DCHECK(IsValid());
DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
diff --git a/runtime/oat.h b/runtime/oat.h
index a9dc540..c864c2c 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -62,6 +62,9 @@ class PACKED(4) OatHeader {
const void* GetPortableResolutionTrampoline() const;
uint32_t GetPortableResolutionTrampolineOffset() const;
void SetPortableResolutionTrampolineOffset(uint32_t offset);
+ const void* GetPortableImtConflictTrampoline() const;
+ uint32_t GetPortableImtConflictTrampolineOffset() const;
+ void SetPortableImtConflictTrampolineOffset(uint32_t offset);
const void* GetPortableToInterpreterBridge() const;
uint32_t GetPortableToInterpreterBridgeOffset() const;
void SetPortableToInterpreterBridgeOffset(uint32_t offset);
@@ -69,6 +72,9 @@ class PACKED(4) OatHeader {
const void* GetQuickResolutionTrampoline() const;
uint32_t GetQuickResolutionTrampolineOffset() const;
void SetQuickResolutionTrampolineOffset(uint32_t offset);
+ const void* GetQuickImtConflictTrampoline() const;
+ uint32_t GetQuickImtConflictTrampolineOffset() const;
+ void SetQuickImtConflictTrampolineOffset(uint32_t offset);
const void* GetQuickToInterpreterBridge() const;
uint32_t GetQuickToInterpreterBridgeOffset() const;
void SetQuickToInterpreterBridgeOffset(uint32_t offset);
@@ -91,8 +97,10 @@ class PACKED(4) OatHeader {
uint32_t interpreter_to_interpreter_bridge_offset_;
uint32_t interpreter_to_compiled_code_bridge_offset_;
uint32_t jni_dlsym_lookup_offset_;
+ uint32_t portable_imt_conflict_trampoline_offset_;
uint32_t portable_resolution_trampoline_offset_;
uint32_t portable_to_interpreter_bridge_offset_;
+ uint32_t quick_imt_conflict_trampoline_offset_;
uint32_t quick_resolution_trampoline_offset_;
uint32_t quick_to_interpreter_bridge_offset_;
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 3ca3c0b..bf25b81 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -458,6 +458,8 @@ class MethodHelper {
Runtime* runtime = Runtime::Current();
if (method_ == runtime->GetResolutionMethod()) {
return "<runtime internal resolution method>";
+ } else if (method_ == runtime->GetImtConflictMethod()) {
+ return "<runtime internal imt conflict method>";
} else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) {
return "<runtime internal callee-save all registers method>";
} else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f46b794..34cf45b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -84,6 +84,8 @@ Runtime::Runtime()
java_vm_(NULL),
pre_allocated_OutOfMemoryError_(NULL),
resolution_method_(NULL),
+ imt_conflict_method_(NULL),
+ default_imt_(NULL),
threads_being_born_(0),
shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)),
shutting_down_(false),
@@ -1175,6 +1177,10 @@ void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) {
}
resolution_method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(resolution_method_, arg));
DCHECK(resolution_method_ != nullptr);
+ imt_conflict_method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(imt_conflict_method_, arg));
+ DCHECK(imt_conflict_method_ != nullptr);
+ default_imt_ = reinterpret_cast<mirror::ObjectArray<mirror::ArtMethod>*>(visitor(default_imt_, arg));
+ DCHECK(default_imt_ != nullptr);
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
callee_save_methods_[i] = reinterpret_cast<mirror::ArtMethod*>(
visitor(callee_save_methods_[i], arg));
@@ -1192,6 +1198,31 @@ void Runtime::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool
VisitNonConcurrentRoots(visitor, arg);
}
+mirror::ObjectArray<mirror::ArtMethod>* Runtime::CreateDefaultImt(ClassLinker* cl) {
+ Thread* self = Thread::Current();
+ SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, cl->AllocArtMethodArray(self, 64));
+ mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
+ for (size_t i = 0; i < 64; i++) {
+ imtable->Set(i, imt_conflict_method);
+ }
+ return imtable.get();
+}
+
+mirror::ArtMethod* Runtime::CreateImtConflictMethod() {
+ mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod();
+ Thread* self = Thread::Current();
+ SirtRef<mirror::ArtMethod>
+ method(self, down_cast<mirror::ArtMethod*>(method_class->AllocObject(self)));
+ method->SetDeclaringClass(method_class);
+ // TODO: use a special method for imt conflict method saves
+ method->SetDexMethodIndex(DexFile::kDexNoIndex);
+ // When compiling, the code pointer will get set later when the image is loaded.
+ Runtime* r = Runtime::Current();
+ ClassLinker* cl = r->GetClassLinker();
+ method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetImtConflictTrampoline(cl));
+ return method.get();
+}
+
mirror::ArtMethod* Runtime::CreateResolutionMethod() {
mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod();
Thread* self = Thread::Current();
diff --git a/runtime/runtime.h b/runtime/runtime.h
index b6429b6..51d9074 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -45,6 +45,7 @@ namespace gc {
namespace mirror {
class ArtMethod;
class ClassLoader;
+ template<class T> class ObjectArray;
template<class T> class PrimitiveArray;
typedef PrimitiveArray<int8_t> ByteArray;
class String;
@@ -349,6 +350,39 @@ class Runtime {
mirror::ArtMethod* CreateResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Returns a special method that calls into a trampoline for runtime imt conflicts
+ mirror::ArtMethod* GetImtConflictMethod() const {
+ CHECK(HasImtConflictMethod());
+ return imt_conflict_method_;
+ }
+
+ bool HasImtConflictMethod() const {
+ return imt_conflict_method_ != NULL;
+ }
+
+ void SetImtConflictMethod(mirror::ArtMethod* method) {
+ imt_conflict_method_ = method;
+ }
+
+ mirror::ArtMethod* CreateImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Returns an imt with every entry set to conflict, used as default imt for all classes.
+ mirror::ObjectArray<mirror::ArtMethod>* GetDefaultImt() const {
+ CHECK(HasDefaultImt());
+ return default_imt_;
+ }
+
+ bool HasDefaultImt() const {
+ return default_imt_ != NULL;
+ }
+
+ void SetDefaultImt(mirror::ObjectArray<mirror::ArtMethod>* imt) {
+ default_imt_ = imt;
+ }
+
+ mirror::ObjectArray<mirror::ArtMethod>* CreateDefaultImt(ClassLinker* cl)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Returns a special method that describes all callee saves being spilled to the stack.
enum CalleeSaveType {
kSaveAll,
@@ -485,6 +519,10 @@ class Runtime {
mirror::ArtMethod* resolution_method_;
+ mirror::ArtMethod* imt_conflict_method_;
+
+ mirror::ObjectArray<mirror::ArtMethod>* default_imt_;
+
// A non-zero value indicates that a thread has been created but not yet initialized. Guarded by
// the shutdown lock so that threads aren't born while we're shutting down.
size_t threads_being_born_ GUARDED_BY(Locks::runtime_shutdown_lock_);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 3063658..9751076 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1555,6 +1555,7 @@ static const EntryPointInfo gThreadEntryPointInfo[] = {
INTERPRETER_ENTRY_POINT_INFO(pInterpreterToInterpreterBridge),
INTERPRETER_ENTRY_POINT_INFO(pInterpreterToCompiledCodeBridge),
JNI_ENTRY_POINT_INFO(pDlsymLookup),
+ PORTABLE_ENTRY_POINT_INFO(pPortableImtConflictTrampoline),
PORTABLE_ENTRY_POINT_INFO(pPortableResolutionTrampoline),
PORTABLE_ENTRY_POINT_INFO(pPortableToInterpreterBridge),
QUICK_ENTRY_POINT_INFO(pAllocArray),
@@ -1617,10 +1618,10 @@ static const EntryPointInfo gThreadEntryPointInfo[] = {
QUICK_ENTRY_POINT_INFO(pMemcmp16),
QUICK_ENTRY_POINT_INFO(pStringCompareTo),
QUICK_ENTRY_POINT_INFO(pMemcpy),
+ QUICK_ENTRY_POINT_INFO(pQuickImtConflictTrampoline),
QUICK_ENTRY_POINT_INFO(pQuickResolutionTrampoline),
QUICK_ENTRY_POINT_INFO(pQuickToInterpreterBridge),
QUICK_ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck),
- QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampoline),
QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck),
QUICK_ENTRY_POINT_INFO(pInvokeStaticTrampolineWithAccessCheck),
QUICK_ENTRY_POINT_INFO(pInvokeSuperTrampolineWithAccessCheck),