Late method resolution.
Change-Id: Ic35348022391c3c11a1d4984b9add7b6ef53aa4c
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e755cbd..095c949 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1352,8 +1352,7 @@
return oat_class;
}
-// Special case to get oat code without overwriting a trampoline.
-const void* ClassLinker::GetOatCodeFor(const Method* method) {
+const OatFile::OatMethod ClassLinker::GetOatMethodFor(const Method* method) {
CHECK(Runtime::Current()->IsCompiler() || method->GetDeclaringClass()->IsInitializing());
// Although we overwrite the trampoline of non-static methods, we may get here via the resolution
// method for direct methods (or virtual methods made direct).
@@ -1380,7 +1379,28 @@
ClassHelper kh(declaring_class);
UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor()));
CHECK(oat_class.get() != NULL);
- return oat_class->GetOatMethod(oat_method_index).GetCode();
+ return oat_class->GetOatMethod(oat_method_index);
+}
+
+// Special case to get oat code without overwriting a trampoline.
+const void* ClassLinker::GetOatCodeFor(const Method* method) {
+ return GetOatMethodFor(method).GetCode();
+}
+
+void ClassLinker::LinkOatCodeFor(Method* method) {
+ Class* declaring_class = method->GetDeclaringClass();
+ ClassHelper kh(declaring_class);
+ const OatFile* oat_file = FindOpenedOatFileForDexFile(kh.GetDexFile());
+ if (oat_file != NULL) {
+ // NOTE: We have to check the availability of OatFile first. Because
+ // GetOatMethodFor(...) will try to find the OatFile and there's
+ // an assert in GetOatMethodFor(...). Besides, due to the return
+ // type of OatClass::GetOatMethod(...), we can't return a failure value
+ // back.
+
+ // TODO: Remove this workaround.
+ GetOatMethodFor(method).LinkMethodPointers(method);
+ }
}
void ClassLinker::FixupStaticTrampolines(Class* klass) {
diff --git a/src/class_linker.h b/src/class_linker.h
index b6727d9..86b02ad 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -290,6 +290,8 @@
// Get the oat code for a method when its class isn't yet initialized
const void* GetOatCodeFor(const Method* method);
+ void LinkOatCodeFor(Method* method);
+
// Relocate the OatFiles (ELF images)
void RelocateExecutable();
@@ -299,6 +301,8 @@
private:
explicit ClassLinker(InternTable*);
+ const OatFile::OatMethod GetOatMethodFor(const Method* method);
+
// Initialize class linker by bootstraping from dex files
void InitFromCompiler(const std::vector<const DexFile*>& boot_class_path);
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index d18080f..874377e 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -141,3 +141,13 @@
declare i32 @art_is_assignable_from_code(%JavaObject*, %JavaObject*)
declare void @art_check_cast_from_code(%JavaObject*, %JavaObject*)
declare void @art_check_put_array_element_from_code(%JavaObject*, %JavaObject*)
+
+declare void @art_ensure_link_from_code(%JavaObject*)
+
+declare %JavaObject* @art_ensure_resolved_from_code(%JavaObject*,
+ %JavaObject*,
+ i32,
+ i32)
+
+declare %JavaObject* @art_ensure_initialized_from_code(%JavaObject*,
+ %JavaObject*)
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index 07fc6a3..2e46efc 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -46,10 +46,10 @@
std::vector<Type*>StructTy_ShadowFrame_fields;
PointerType* PointerTy_2 = PointerType::get(StructTy_ShadowFrame, 0);
-StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
StructTy_ShadowFrame_fields.push_back(PointerTy_2);
StructTy_ShadowFrame_fields.push_back(PointerTy_1);
StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
+StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
if (StructTy_ShadowFrame->isOpaque()) {
StructTy_ShadowFrame->setBody(StructTy_ShadowFrame_fields, /*isPacked=*/false);
}
@@ -244,7 +244,7 @@
FuncTy_25_args.push_back(PointerTy_1);
FuncTy_25_args.push_back(PointerTy_1);
FunctionType* FuncTy_25 = FunctionType::get(
- /*Result=*/IntegerType::get(mod->getContext(), 32),
+ /*Result=*/PointerTy_1,
/*Params=*/FuncTy_25_args,
/*isVarArg=*/false);
@@ -252,7 +252,7 @@
FuncTy_26_args.push_back(PointerTy_1);
FuncTy_26_args.push_back(PointerTy_1);
FunctionType* FuncTy_26 = FunctionType::get(
- /*Result=*/Type::getVoidTy(mod->getContext()),
+ /*Result=*/IntegerType::get(mod->getContext(), 32),
/*Params=*/FuncTy_26_args,
/*isVarArg=*/false);
@@ -260,10 +260,20 @@
FuncTy_27_args.push_back(PointerTy_1);
FuncTy_27_args.push_back(PointerTy_1);
FunctionType* FuncTy_27 = FunctionType::get(
- /*Result=*/PointerTy_1,
+ /*Result=*/Type::getVoidTy(mod->getContext()),
/*Params=*/FuncTy_27_args,
/*isVarArg=*/false);
+std::vector<Type*>FuncTy_28_args;
+FuncTy_28_args.push_back(PointerTy_1);
+FuncTy_28_args.push_back(PointerTy_1);
+FuncTy_28_args.push_back(IntegerType::get(mod->getContext(), 32));
+FuncTy_28_args.push_back(IntegerType::get(mod->getContext(), 32));
+FunctionType* FuncTy_28 = FunctionType::get(
+ /*Result=*/PointerTy_1,
+ /*Params=*/FuncTy_28_args,
+ /*isVarArg=*/false);
+
// Function Declarations
@@ -743,7 +753,7 @@
Function* func_art_decode_jobject_in_thread = mod->getFunction("art_decode_jobject_in_thread");
if (!func_art_decode_jobject_in_thread) {
func_art_decode_jobject_in_thread = Function::Create(
- /*Type=*/FuncTy_27,
+ /*Type=*/FuncTy_25,
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"art_decode_jobject_in_thread", mod); // (external, no body)
func_art_decode_jobject_in_thread->setCallingConv(CallingConv::C);
@@ -754,7 +764,7 @@
Function* func_art_is_assignable_from_code = mod->getFunction("art_is_assignable_from_code");
if (!func_art_is_assignable_from_code) {
func_art_is_assignable_from_code = Function::Create(
- /*Type=*/FuncTy_25,
+ /*Type=*/FuncTy_26,
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"art_is_assignable_from_code", mod); // (external, no body)
func_art_is_assignable_from_code->setCallingConv(CallingConv::C);
@@ -765,7 +775,7 @@
Function* func_art_check_cast_from_code = mod->getFunction("art_check_cast_from_code");
if (!func_art_check_cast_from_code) {
func_art_check_cast_from_code = Function::Create(
- /*Type=*/FuncTy_26,
+ /*Type=*/FuncTy_27,
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"art_check_cast_from_code", mod); // (external, no body)
func_art_check_cast_from_code->setCallingConv(CallingConv::C);
@@ -784,6 +794,39 @@
AttrListPtr func_art_check_put_array_element_from_code_PAL;
func_art_check_put_array_element_from_code->setAttributes(func_art_check_put_array_element_from_code_PAL);
+Function* func_art_ensure_link_from_code = mod->getFunction("art_ensure_link_from_code");
+if (!func_art_ensure_link_from_code) {
+func_art_ensure_link_from_code = Function::Create(
+ /*Type=*/FuncTy_4,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_ensure_link_from_code", mod); // (external, no body)
+func_art_ensure_link_from_code->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_ensure_link_from_code_PAL;
+func_art_ensure_link_from_code->setAttributes(func_art_ensure_link_from_code_PAL);
+
+Function* func_art_ensure_resolved_from_code = mod->getFunction("art_ensure_resolved_from_code");
+if (!func_art_ensure_resolved_from_code) {
+func_art_ensure_resolved_from_code = Function::Create(
+ /*Type=*/FuncTy_28,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_ensure_resolved_from_code", mod); // (external, no body)
+func_art_ensure_resolved_from_code->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_ensure_resolved_from_code_PAL;
+func_art_ensure_resolved_from_code->setAttributes(func_art_ensure_resolved_from_code_PAL);
+
+Function* func_art_ensure_initialized_from_code = mod->getFunction("art_ensure_initialized_from_code");
+if (!func_art_ensure_initialized_from_code) {
+func_art_ensure_initialized_from_code = Function::Create(
+ /*Type=*/FuncTy_25,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_ensure_initialized_from_code", mod); // (external, no body)
+func_art_ensure_initialized_from_code->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_ensure_initialized_from_code_PAL;
+func_art_ensure_initialized_from_code->setAttributes(func_art_ensure_initialized_from_code_PAL);
+
// Global Variable Declarations
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index 285caab..071c0bd 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -145,11 +145,20 @@
irb_.getInt32(Thread::kNative));
// Get callee code_addr
- llvm::Value* code_addr =
+ llvm::Value* code_addr_ =
LoadFromObjectOffset(method_object_addr,
Method::NativeMethodOffset().Int32Value(),
GetFunctionType(method_idx_, is_static, true)->getPointerTo());
+ llvm::Value* code_addr;
+ llvm::FunctionType* method_type = GetFunctionType(method_idx_, is_static, true);
+ // TODO: Inline check
+ llvm::Value* runtime_func = irb_.GetRuntime(runtime_support::EnsureInitialized);
+ llvm::Value* result = irb_.CreateCall2(runtime_func,
+ method_object_addr,
+ irb_.CreatePointerCast(code_addr_,
+ irb_.getJObjectTy()));
+ code_addr = irb_.CreatePointerCast(result, method_type->getPointerTo());
// Load actual parameters
std::vector<llvm::Value*> args;
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 57dbf15..7c19774 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -2785,6 +2785,39 @@
<< PrettyMethod(callee_method_idx, *dex_file_);
}
+llvm::Value* MethodCompiler::EmitEnsureInitialized(llvm::Value* callee_method_object_addr,
+ uint32_t method_idx,
+ bool is_static,
+ llvm::Value* code_addr) {
+ llvm::FunctionType* method_type = GetFunctionType(method_idx, is_static);
+
+ // TODO: Inline check
+ llvm::Value* runtime_func = irb_.GetRuntime(EnsureInitialized);
+ llvm::Value* result = irb_.CreateCall2(runtime_func,
+ callee_method_object_addr,
+ irb_.CreatePointerCast(code_addr,
+ irb_.getJObjectTy()));
+ return irb_.CreatePointerCast(result, method_type->getPointerTo());
+}
+
+llvm::Value* MethodCompiler::EmitEnsureResolved(llvm::Value* callee,
+ llvm::Value* caller,
+ uint32_t dex_method_idx,
+ Instruction::Code instr_code) {
+ // TODO: Inline check
+ llvm::Value* runtime_func = irb_.GetRuntime(EnsureResolved);
+ return irb_.CreateCall4(runtime_func,
+ callee,
+ caller,
+ irb_.getInt32(dex_method_idx),
+ irb_.getInt32(instr_code));
+}
+
+void MethodCompiler::EmitEnsureLink(llvm::Value* method_object_addr) {
+ // TODO: Inline check
+ llvm::Value* runtime_func = irb_.GetRuntime(EnsureLink);
+ irb_.CreateCall(runtime_func, method_object_addr);
+}
void MethodCompiler::EmitInsn_InvokeVirtualSuperSlow(uint32_t dex_pc,
DecodedInstruction &dec_insn,
@@ -2812,14 +2845,28 @@
EmitUpdateLineNumFromDexPC(dex_pc);
- llvm::Value* callee_method_object_addr =
+ llvm::Value* callee_method_object_addr_ =
irb_.CreateCall3(runtime_func,
callee_method_idx_value, this_addr, method_object_addr);
EmitGuard_ExceptionLandingPad(dex_pc);
- llvm::Value* code_addr =
+ llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+ method_object_addr,
+ callee_method_idx,
+ (is_virtual ?
+ Instruction::INVOKE_VIRTUAL :
+ Instruction::INVOKE_SUPER));
+
+ EmitEnsureLink(callee_method_object_addr);
+
+ llvm::Value* code_addr_ =
EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, false);
+
+ llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+ callee_method_idx,
+ false,
+ code_addr_);
// Load the actual parameter
std::vector<llvm::Value*> args;
args.push_back(callee_method_object_addr);
@@ -2864,13 +2911,25 @@
// Load callee method code address (branch destination)
llvm::Value* vtable_addr = EmitLoadVTableAddr(class_object_addr);
- llvm::Value* method_object_addr =
+ llvm::Value* method_object_addr_ =
EmitLoadMethodObjectAddrFromVTable(vtable_addr,
callee_method->GetMethodIndex());
- llvm::Value* code_addr =
+ llvm::Value* method_object_addr = EmitEnsureResolved(method_object_addr_,
+ EmitLoadMethodObjectAddr(),
+ callee_method_idx,
+ Instruction::INVOKE_VIRTUAL);
+
+ EmitEnsureLink(method_object_addr);
+
+ llvm::Value* code_addr_ =
EmitLoadCodeAddr(method_object_addr, callee_method_idx, false);
+ llvm::Value* code_addr = EmitEnsureInitialized(method_object_addr,
+ callee_method_idx,
+ false,
+ code_addr_);
+
// Load actual parameters
std::vector<llvm::Value*> args;
args.push_back(method_object_addr);
@@ -2953,14 +3012,26 @@
// Load method object from virtual table
llvm::Value* vtable_addr = EmitLoadVTableAddr(super_class_addr);
- llvm::Value* callee_method_object_addr =
+ llvm::Value* callee_method_object_addr_ =
EmitLoadMethodObjectAddrFromVTable(vtable_addr,
callee_method->GetMethodIndex());
- llvm::Value* code_addr =
+ llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+ method_object_addr,
+ callee_method_idx,
+ Instruction::INVOKE_SUPER);
+
+ EmitEnsureLink(callee_method_object_addr);
+
+ llvm::Value* code_addr_ =
EmitLoadCodeAddr(callee_method_object_addr,
callee_method_idx, false);
+ llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+ callee_method_idx,
+ false,
+ code_addr_);
+
// Load actual parameters
std::vector<llvm::Value*> args;
args.push_back(callee_method_object_addr);
@@ -3019,12 +3090,25 @@
llvm::Value* callee_method_object_field_addr =
EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
- llvm::Value* callee_method_object_addr =
+ llvm::Value* callee_method_object_addr_ =
irb_.CreateLoad(callee_method_object_field_addr);
- llvm::Value* code_addr =
+ llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+ EmitLoadMethodObjectAddr(),
+ callee_method_idx,
+ Instruction::INVOKE_DIRECT);
+
+ EmitEnsureLink(callee_method_object_addr);
+
+ llvm::Value* code_addr_ =
EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, is_static);
+ llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+ callee_method_idx,
+ is_static,
+ code_addr_);
+ EmitGuard_ExceptionLandingPad(dex_pc);
+
// Load the actual parameter
std::vector<llvm::Value*> args;
@@ -3075,15 +3159,27 @@
EmitUpdateLineNumFromDexPC(dex_pc);
- llvm::Value* callee_method_object_addr =
+ llvm::Value* callee_method_object_addr_ =
irb_.CreateCall3(runtime_func,
callee_method_idx_value, this_addr, method_object_addr);
EmitGuard_ExceptionLandingPad(dex_pc);
- llvm::Value* code_addr =
+ llvm::Value* callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr_,
+ method_object_addr,
+ callee_method_idx,
+ Instruction::INVOKE_INTERFACE);
+
+ EmitEnsureLink(callee_method_object_addr);
+
+ llvm::Value* code_addr_ =
EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, false);
+ llvm::Value* code_addr = EmitEnsureInitialized(callee_method_object_addr,
+ callee_method_idx,
+ false,
+ code_addr_);
+
// Load the actual parameter
std::vector<llvm::Value*> args;
args.push_back(callee_method_object_addr);
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 1ff3a9f..e5be3ba 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -194,6 +194,16 @@
void EmitInsn_SPut(GEN_INSN_ARGS, JType field_jty);
// INVOKE instructions
+ llvm::Value* EmitEnsureInitialized(llvm::Value* callee_method_object_addr,
+ uint32_t method_idx,
+ bool is_static,
+ llvm::Value* code_addr);
+ llvm::Value* EmitEnsureResolved(llvm::Value* callee,
+ llvm::Value* caller,
+ uint32_t dex_method_idx,
+ Instruction::Code instr_code);
+ void EmitEnsureLink(llvm::Value*);
+
void EmitInsn_InvokeVirtual(GEN_INSN_ARGS, bool is_range);
void EmitInsn_InvokeSuper(GEN_INSN_ARGS, bool is_range);
void EmitInsn_InvokeVirtualSuperSlow(uint32_t dex_pc,
diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h
index 518a175..2f1fb13 100644
--- a/src/compiler_llvm/runtime_support_func_list.h
+++ b/src/compiler_llvm/runtime_support_func_list.h
@@ -57,4 +57,7 @@
V(InitializeStaticStorage, art_initialize_static_storage_from_code) \
V(IsExceptionPending, art_is_exception_pending_from_code) \
V(FindCatchBlock, art_find_catch_block_from_code) \
+ V(EnsureInitialized, art_ensure_initialized_from_code) \
+ V(EnsureLink, art_ensure_link_from_code) \
+ V(EnsureResolved, art_ensure_resolved_from_code) \
V(DecodeJObjectInThread, art_decode_jobject_in_thread)
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index ff31825..57fd507 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -517,6 +517,94 @@
}
}
+const void* art_ensure_initialized_from_code(Method* called,
+ void* code) {
+ if (LIKELY(code != Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod)->GetData())) {
+ return code;
+ }
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ Class* called_class = called->GetDeclaringClass();
+ linker->EnsureInitialized(called_class, true, true);
+ if (LIKELY(called_class->IsInitialized())) {
+ return called->GetCode();
+ } else if (called_class->IsInitializing()) {
+ return linker->GetOatCodeFor(called);
+ } else {
+ DCHECK(called_class->IsErroneous());
+ return code;
+ }
+}
+
+Method* art_ensure_resolved_from_code(Method* called,
+ Method* caller,
+ uint32_t dex_method_idx,
+ Instruction::Code instr_code) {
+ if (LIKELY(!called->IsResolutionMethod())) {
+ return called;
+ }
+ // Compute details about the called method (avoid GCs)
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ bool is_static = (instr_code == Instruction::INVOKE_STATIC) ||
+ (instr_code == Instruction::INVOKE_STATIC_RANGE);
+
+ bool is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
+ (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
+ (instr_code == Instruction::INVOKE_SUPER) ||
+ (instr_code == Instruction::INVOKE_SUPER_RANGE);
+
+ DCHECK(is_static || is_virtual ||
+ (instr_code == Instruction::INVOKE_DIRECT) ||
+ (instr_code == Instruction::INVOKE_DIRECT_RANGE));
+
+ called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
+
+ const void* code = NULL;
+ Thread* thread = art_get_current_thread_from_code();
+ if (LIKELY(!thread->IsExceptionPending())) {
+ if (LIKELY(called->IsDirect() == !is_virtual)) {
+ // Ensure that the called method's class is initialized.
+ Class* called_class = called->GetDeclaringClass();
+ linker->EnsureInitialized(called_class, true, true);
+ if (LIKELY(called_class->IsInitialized())) {
+ code = called->GetCode();
+ } else if (called_class->IsInitializing()) {
+ if (is_static) {
+ // Class is still initializing, go to oat and grab code (trampoline must be left in place
+ // until class is initialized to stop races between threads).
+ code = linker->GetOatCodeFor(called);
+ LOG(FATAL) << "Is static";
+ } else {
+ // No trampoline for non-static methods.
+ code = called->GetCode();
+ }
+ } else {
+ DCHECK(called_class->IsErroneous());
+ LOG(FATAL) << "Is erroneous";
+ }
+ } else {
+ // Direct method has been made virtual
+ thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+ "Expected direct method but found virtual: %s",
+ PrettyMethod(called, true).c_str());
+ }
+ }
+
+ if (code != NULL) {
+ // Expect class to at least be initializing.
+ DCHECK(called->GetDeclaringClass()->IsInitializing());
+ // Don't want infinite recursion.
+ DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
+ }
+
+ return called;
+}
+
+void art_ensure_link_from_code(Method* method) {
+ if (method->GetInvokeStub() == NULL && method->GetCode() == NULL) {
+ Runtime::Current()->GetClassLinker()->LinkOatCodeFor(method);
+ }
+}
+
void* art_find_runtime_support_func(void* context, char const* name) {
struct func_entry_t {
char const* name;
diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h
index 51d238b..1040b90 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -19,6 +19,9 @@
namespace art {
+class Method;
+class Object;
+
//----------------------------------------------------------------------------
// Thread
//----------------------------------------------------------------------------
@@ -59,6 +62,8 @@
void* art_find_runtime_support_func(void* context, char const* name);
+void art_ensure_link_from_code(Method* method);
+
} // namespace art
#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_H_
diff --git a/src/compiler_llvm/upcall_compiler.cc b/src/compiler_llvm/upcall_compiler.cc
index 85bfe24..6d14a19 100644
--- a/src/compiler_llvm/upcall_compiler.cc
+++ b/src/compiler_llvm/upcall_compiler.cc
@@ -151,7 +151,15 @@
irb_.CreatePtrDisp(method_object_addr, code_field_offset_value,
accurate_func_type->getPointerTo()->getPointerTo());
- llvm::Value* code_addr = irb_.CreateLoad(code_field_addr);
+ llvm::Value* code_addr_ = irb_.CreateLoad(code_field_addr);
+ llvm::Value* code_addr;
+ // TODO: Inline check
+ llvm::Value* runtime_func = irb_.GetRuntime(runtime_support::EnsureInitialized);
+ llvm::Value* result = irb_.CreateCall2(runtime_func,
+ method_object_addr,
+ irb_.CreatePointerCast(code_addr_,
+ irb_.getJObjectTy()));
+ code_addr = irb_.CreatePointerCast(result, accurate_func_type->getPointerTo());
llvm::Value* retval = irb_.CreateCall(code_addr, args);
diff --git a/src/object.cc b/src/object.cc
index 2cf8a6c..f2bddc3 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -40,6 +40,7 @@
#if defined(ART_USE_LLVM_COMPILER)
#include "compiler_llvm/inferred_reg_category_map.h"
+#include "compiler_llvm/runtime_support_llvm.h"
using art::compiler_llvm::InferredRegCategoryMap;
#endif
@@ -559,6 +560,7 @@
void Method::Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) const {
// Push a transition back into managed code onto the linked list in thread.
CHECK_EQ(Thread::kRunnable, self->GetState());
+
#if !defined(ART_USE_LLVM_COMPILER)
NativeToManagedRecord record;
self->PushNativeToManagedRecord(&record);
@@ -570,6 +572,14 @@
bool have_executable_code = (GetCode() != NULL);
+#if defined(ART_USE_LLVM_COMPILER)
+ if (stub == NULL && !have_executable_code) {
+ art_ensure_link_from_code(const_cast<Method*>(this));
+ stub = GetInvokeStub();
+ have_executable_code = (GetCode() != NULL);
+ }
+#endif
+
if (Runtime::Current()->IsStarted() && have_executable_code && stub != NULL) {
bool log = false;
if (log) {