Fix 065 and 066 tests (slow path). Refactor invoke-* instructions.
Refactor invoke-static, invoke-direct, invoke-virtual,
invoke-super, and invoke-interface and implement the
slow path for invoke-static and invoke-direct.
Change-Id: I21ce11ad2ce62a0660f26f16373572493d9bf2d3
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index 1ca556b..9354bb6 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -85,9 +85,18 @@
declare void @art_find_instance_field_from_code(i32, %JavaObject*)
declare void @art_find_static_field_from_code(i32, %JavaObject*)
-declare %JavaObject* @art_find_interface_method_from_code(i32, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_find_virtual_method_from_code(i32, %JavaObject*, %JavaObject*)
-declare %JavaObject* @art_find_super_method_from_code(i32, %JavaObject*, %JavaObject*)
+declare %JavaObject* @art_find_static_method_from_code_with_access_check(
+ i32, %JavaObject*, %JavaObject*)
+declare %JavaObject* @art_find_direct_method_from_code_with_access_check(
+ i32, %JavaObject*, %JavaObject*)
+declare %JavaObject* @art_find_virtual_method_from_code_with_access_check(
+ i32, %JavaObject*, %JavaObject*)
+declare %JavaObject* @art_find_super_method_from_code_with_access_check(
+ i32, %JavaObject*, %JavaObject*)
+declare %JavaObject* @art_find_interface_method_from_code_with_access_check(
+ i32, %JavaObject*, %JavaObject*)
+declare %JavaObject* @art_find_interface_method_from_code(
+ i32, %JavaObject*, %JavaObject*)
declare %JavaObject* @art_initialize_static_storage_from_code(i32, %JavaObject*)
declare %JavaObject* @art_initialize_type_from_code(i32, %JavaObject*)
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index e327c00..6889ed9 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -568,6 +568,61 @@
AttrListPtr func_art_find_static_field_from_code_PAL;
func_art_find_static_field_from_code->setAttributes(func_art_find_static_field_from_code_PAL);
+Function* func_art_find_static_method_from_code_with_access_check = mod->getFunction("art_find_static_method_from_code_with_access_check");
+if (!func_art_find_static_method_from_code_with_access_check) {
+func_art_find_static_method_from_code_with_access_check = Function::Create(
+ /*Type=*/FuncTy_15,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_find_static_method_from_code_with_access_check", mod); // (external, no body)
+func_art_find_static_method_from_code_with_access_check->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_find_static_method_from_code_with_access_check_PAL;
+func_art_find_static_method_from_code_with_access_check->setAttributes(func_art_find_static_method_from_code_with_access_check_PAL);
+
+Function* func_art_find_direct_method_from_code_with_access_check = mod->getFunction("art_find_direct_method_from_code_with_access_check");
+if (!func_art_find_direct_method_from_code_with_access_check) {
+func_art_find_direct_method_from_code_with_access_check = Function::Create(
+ /*Type=*/FuncTy_15,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_find_direct_method_from_code_with_access_check", mod); // (external, no body)
+func_art_find_direct_method_from_code_with_access_check->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_find_direct_method_from_code_with_access_check_PAL;
+func_art_find_direct_method_from_code_with_access_check->setAttributes(func_art_find_direct_method_from_code_with_access_check_PAL);
+
+Function* func_art_find_virtual_method_from_code_with_access_check = mod->getFunction("art_find_virtual_method_from_code_with_access_check");
+if (!func_art_find_virtual_method_from_code_with_access_check) {
+func_art_find_virtual_method_from_code_with_access_check = Function::Create(
+ /*Type=*/FuncTy_15,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_find_virtual_method_from_code_with_access_check", mod); // (external, no body)
+func_art_find_virtual_method_from_code_with_access_check->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_find_virtual_method_from_code_with_access_check_PAL;
+func_art_find_virtual_method_from_code_with_access_check->setAttributes(func_art_find_virtual_method_from_code_with_access_check_PAL);
+
+Function* func_art_find_super_method_from_code_with_access_check = mod->getFunction("art_find_super_method_from_code_with_access_check");
+if (!func_art_find_super_method_from_code_with_access_check) {
+func_art_find_super_method_from_code_with_access_check = Function::Create(
+ /*Type=*/FuncTy_15,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_find_super_method_from_code_with_access_check", mod); // (external, no body)
+func_art_find_super_method_from_code_with_access_check->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_find_super_method_from_code_with_access_check_PAL;
+func_art_find_super_method_from_code_with_access_check->setAttributes(func_art_find_super_method_from_code_with_access_check_PAL);
+
+Function* func_art_find_interface_method_from_code_with_access_check = mod->getFunction("art_find_interface_method_from_code_with_access_check");
+if (!func_art_find_interface_method_from_code_with_access_check) {
+func_art_find_interface_method_from_code_with_access_check = Function::Create(
+ /*Type=*/FuncTy_15,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_find_interface_method_from_code_with_access_check", mod); // (external, no body)
+func_art_find_interface_method_from_code_with_access_check->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_find_interface_method_from_code_with_access_check_PAL;
+func_art_find_interface_method_from_code_with_access_check->setAttributes(func_art_find_interface_method_from_code_with_access_check_PAL);
+
Function* func_art_find_interface_method_from_code = mod->getFunction("art_find_interface_method_from_code");
if (!func_art_find_interface_method_from_code) {
func_art_find_interface_method_from_code = Function::Create(
@@ -579,28 +634,6 @@
AttrListPtr func_art_find_interface_method_from_code_PAL;
func_art_find_interface_method_from_code->setAttributes(func_art_find_interface_method_from_code_PAL);
-Function* func_art_find_virtual_method_from_code = mod->getFunction("art_find_virtual_method_from_code");
-if (!func_art_find_virtual_method_from_code) {
-func_art_find_virtual_method_from_code = Function::Create(
- /*Type=*/FuncTy_15,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_find_virtual_method_from_code", mod); // (external, no body)
-func_art_find_virtual_method_from_code->setCallingConv(CallingConv::C);
-}
-AttrListPtr func_art_find_virtual_method_from_code_PAL;
-func_art_find_virtual_method_from_code->setAttributes(func_art_find_virtual_method_from_code_PAL);
-
-Function* func_art_find_super_method_from_code = mod->getFunction("art_find_super_method_from_code");
-if (!func_art_find_super_method_from_code) {
-func_art_find_super_method_from_code = Function::Create(
- /*Type=*/FuncTy_15,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_find_super_method_from_code", mod); // (external, no body)
-func_art_find_super_method_from_code->setCallingConv(CallingConv::C);
-}
-AttrListPtr func_art_find_super_method_from_code_PAL;
-func_art_find_super_method_from_code->setAttributes(func_art_find_super_method_from_code_PAL);
-
Function* func_art_initialize_static_storage_from_code = mod->getFunction("art_initialize_static_storage_from_code");
if (!func_art_initialize_static_storage_from_code) {
func_art_initialize_static_storage_from_code = Function::Create(
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index d3d7e39..8932b47 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -708,43 +708,43 @@
case Instruction::INVOKE_VIRTUAL:
- EmitInsn_InvokeVirtual(ARGS, false);
+ EmitInsn_Invoke(ARGS, kVirtual, kArgReg);
break;
case Instruction::INVOKE_SUPER:
- EmitInsn_InvokeSuper(ARGS, false);
+ EmitInsn_Invoke(ARGS, kSuper, kArgReg);
break;
case Instruction::INVOKE_DIRECT:
- EmitInsn_InvokeStaticDirect(ARGS, kDirect, /* is_range */ false);
+ EmitInsn_Invoke(ARGS, kDirect, kArgReg);
break;
case Instruction::INVOKE_STATIC:
- EmitInsn_InvokeStaticDirect(ARGS, kStatic, /* is_range */ false);
+ EmitInsn_Invoke(ARGS, kStatic, kArgReg);
break;
case Instruction::INVOKE_INTERFACE:
- EmitInsn_InvokeInterface(ARGS, false);
+ EmitInsn_Invoke(ARGS, kInterface, kArgReg);
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
- EmitInsn_InvokeVirtual(ARGS, true);
+ EmitInsn_Invoke(ARGS, kVirtual, kArgRange);
break;
case Instruction::INVOKE_SUPER_RANGE:
- EmitInsn_InvokeSuper(ARGS, true);
+ EmitInsn_Invoke(ARGS, kSuper, kArgRange);
break;
case Instruction::INVOKE_DIRECT_RANGE:
- EmitInsn_InvokeStaticDirect(ARGS, kDirect, true);
+ EmitInsn_Invoke(ARGS, kDirect, kArgRange);
break;
case Instruction::INVOKE_STATIC_RANGE:
- EmitInsn_InvokeStaticDirect(ARGS, kStatic, true);
+ EmitInsn_Invoke(ARGS, kStatic, kArgRange);
break;
case Instruction::INVOKE_INTERFACE_RANGE:
- EmitInsn_InvokeInterface(ARGS, true);
+ EmitInsn_Invoke(ARGS, kInterface, kArgRange);
break;
case Instruction::NEG_INT:
@@ -2488,35 +2488,6 @@
}
-Method* MethodCompiler::ResolveMethod(uint32_t method_idx) {
- Thread* thread = Thread::Current();
-
- // Save the exception state
- Throwable* old_exception = NULL;
- if (thread->IsExceptionPending()) {
- old_exception = thread->GetException();
- thread->ClearException();
- }
-
- // Resolve the method through the class linker
- Method* method = class_linker_->ResolveMethod(*dex_file_, method_idx,
- dex_cache_, class_loader_,
- /* is_direct= */ false);
-
- if (method == NULL) {
- // Ignore the exception raised during the method resolution
- thread->ClearException();
- }
-
- // Restore the exception state
- if (old_exception != NULL) {
- thread->SetException(old_exception);
- }
-
- return method;
-}
-
-
Field* MethodCompiler::ResolveField(uint32_t field_idx) {
Thread* thread = Thread::Current();
@@ -2753,20 +2724,11 @@
}
-llvm::Value* MethodCompiler::EmitLoadCalleeThis(DecodedInstruction const& dec_insn, bool is_range) {
- if (is_range) {
- return EmitLoadDalvikReg(dec_insn.vC, kObject, kAccurate);
- } else {
- return EmitLoadDalvikReg(dec_insn.arg[0], kObject, kAccurate);
- }
-}
-
-
void MethodCompiler::
EmitLoadActualParameters(std::vector<llvm::Value*>& args,
uint32_t callee_method_idx,
DecodedInstruction const& dec_insn,
- bool is_range,
+ InvokeArgFmt arg_fmt,
bool is_static) {
// Get method signature
@@ -2784,6 +2746,8 @@
++reg_count; // skip the "this" pointer
}
+ bool is_range = (arg_fmt == kArgRange);
+
for (uint32_t i = 1; i < shorty_size; ++i) {
uint32_t reg_idx = (is_range) ? (dec_insn.vC + reg_count)
: (dec_insn.arg[reg_count]);
@@ -2826,293 +2790,101 @@
return irb_.CreatePointerCast(code_addr, method_type->getPointerTo());
}
-void MethodCompiler::EmitInsn_InvokeVirtualSuperSlow(uint32_t dex_pc,
- DecodedInstruction &dec_insn,
- bool is_range,
- uint32_t callee_method_idx,
- bool is_virtual) {
- // Callee method can't be resolved at compile time. Emit the runtime
- // method resolution code.
- // Test: Is "this" pointer equal to null?
- llvm::Value* this_addr = EmitLoadCalleeThis(dec_insn, is_range);
- EmitGuard_NullPointerException(dex_pc, this_addr);
-
- // Resolve the callee method object address at runtime
- llvm::Value* runtime_func;
- if (is_virtual) {
- runtime_func = irb_.GetRuntime(FindVirtualMethod);
- } else {
- runtime_func = irb_.GetRuntime(FindSuperMethod);
- }
-
- llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
- llvm::Value* callee_method_idx_value = irb_.getInt32(callee_method_idx);
-
- EmitUpdateLineNumFromDexPC(dex_pc);
-
- llvm::Value* callee_method_object_addr =
- irb_.CreateCall3(runtime_func,
- callee_method_idx_value, this_addr, method_object_addr);
-
- EmitGuard_ExceptionLandingPad(dex_pc);
-
-#if 0
- llvm::Value* code_addr =
- EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, false);
-#else
- // TODO: Remove this after we solve the link and trampoline related problems.
- llvm::Value* code_addr = EmitFixStub(callee_method_object_addr,
- callee_method_idx,
- false);
- EmitGuard_ExceptionLandingPad(dex_pc);
-#endif
-
- // Load the actual parameter
- std::vector<llvm::Value*> args;
- args.push_back(callee_method_object_addr);
- args.push_back(this_addr);
- EmitLoadActualParameters(args, callee_method_idx, dec_insn, is_range, false);
-
- // Invoke callee
- EmitUpdateLineNumFromDexPC(dex_pc);
- llvm::Value* retval = irb_.CreateCall(code_addr, args);
- EmitGuard_ExceptionLandingPad(dex_pc);
-
- UniquePtr<OatCompilationUnit>
- callee(oat_compilation_unit_->GetCallee(callee_method_idx, /* access flags */ 0));
- char ret_shorty = callee->GetShorty()[0];
- if (ret_shorty != 'V') {
- EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval);
- }
-}
-
-void MethodCompiler::EmitInsn_InvokeVirtual(uint32_t dex_pc,
- Instruction const* insn,
- bool is_range) {
-
+void MethodCompiler::EmitInsn_Invoke(uint32_t dex_pc,
+ Instruction const* insn,
+ InvokeType invoke_type,
+ InvokeArgFmt arg_fmt) {
DecodedInstruction dec_insn(insn);
- uint32_t callee_method_idx = dec_insn.vB;
-
- // Find the method object at compile time
- Method* callee_method = ResolveMethod(callee_method_idx);
-
- if (callee_method == NULL) {
- EmitInsn_InvokeVirtualSuperSlow(dex_pc, dec_insn, is_range,
- callee_method_idx, /*is_virtual*/ true);
- } else {
- // Test: Is *this* parameter equal to null?
- llvm::Value* this_addr = EmitLoadCalleeThis(dec_insn, is_range);
- EmitGuard_NullPointerException(dex_pc, this_addr);
-
- // Load class object of *this* pointer
- llvm::Value* class_object_addr = EmitLoadClassObjectAddr(this_addr);
-
- // Load callee method code address (branch destination)
- llvm::Value* vtable_addr = EmitLoadVTableAddr(class_object_addr);
-
- llvm::Value* method_object_addr =
- EmitLoadMethodObjectAddrFromVTable(vtable_addr,
- callee_method->GetMethodIndex());
-
-#if 0
- llvm::Value* code_addr =
- EmitLoadCodeAddr(method_object_addr, callee_method_idx, false);
-#else
- // TODO: Remove this after we solve the link and trampoline related problems.
- method_object_addr = EmitEnsureResolved(method_object_addr,
- EmitLoadMethodObjectAddr(),
- callee_method_idx,
- true);
- EmitGuard_ExceptionLandingPad(dex_pc);
-
- llvm::Value* code_addr = EmitFixStub(method_object_addr,
- callee_method_idx,
- false);
- EmitGuard_ExceptionLandingPad(dex_pc);
-#endif
- // Load actual parameters
- std::vector<llvm::Value*> args;
- args.push_back(method_object_addr);
- args.push_back(this_addr);
- EmitLoadActualParameters(args, callee_method_idx, dec_insn,
- is_range, false);
-
- // Invoke callee
- EmitUpdateLineNumFromDexPC(dex_pc);
- llvm::Value* retval = irb_.CreateCall(code_addr, args);
- EmitGuard_ExceptionLandingPad(dex_pc);
-
- MethodHelper method_helper(callee_method);
- char ret_shorty = method_helper.GetShorty()[0];
- if (ret_shorty != 'V') {
- EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval);
- }
- }
-
- irb_.CreateBr(GetNextBasicBlock(dex_pc));
-}
-
-
-void MethodCompiler::EmitInsn_InvokeSuper(uint32_t dex_pc,
- Instruction const* insn,
- bool is_range) {
-
- DecodedInstruction dec_insn(insn);
-
- uint32_t callee_method_idx = dec_insn.vB;
-
- // Find the method object at compile time
- Method* callee_overiding_method = ResolveMethod(callee_method_idx);
-
- if (callee_overiding_method == NULL) {
- EmitInsn_InvokeVirtualSuperSlow(dex_pc, dec_insn, is_range,
- callee_method_idx, /*is_virtual*/ false);
- } else {
- // CHECK: Is the instruction well-encoded or is the class hierarchy correct?
- Class* declaring_class = method_->GetDeclaringClass();
- CHECK_NE(declaring_class, static_cast<Class*>(NULL));
-
- Class* super_class = declaring_class->GetSuperClass();
- CHECK_NE(super_class, static_cast<Class*>(NULL));
-
- uint16_t callee_method_index = callee_overiding_method->GetMethodIndex();
- CHECK_GT(super_class->GetVTable()->GetLength(), callee_method_index);
-
- Method* callee_method = super_class->GetVTable()->Get(callee_method_index);
- CHECK_NE(callee_method, static_cast<Method*>(NULL));
-
- // Test: Is *this* parameter equal to null?
- llvm::Value* this_addr = EmitLoadCalleeThis(dec_insn, is_range);
- EmitGuard_NullPointerException(dex_pc, this_addr);
-
- // Load declaring class of the caller method
- llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
-
- llvm::ConstantInt* declaring_class_offset_value =
- irb_.getPtrEquivInt(Method::DeclaringClassOffset().Int32Value());
-
- llvm::Value* declaring_class_field_addr =
- irb_.CreatePtrDisp(method_object_addr, declaring_class_offset_value,
- irb_.getJObjectTy()->getPointerTo());
-
- llvm::Value* declaring_class_addr =
- irb_.CreateLoad(declaring_class_field_addr);
-
- // Load the super class of the declaring class
- llvm::Value* super_class_offset_value =
- irb_.getPtrEquivInt(Class::SuperClassOffset().Int32Value());
-
- llvm::Value* super_class_field_addr =
- irb_.CreatePtrDisp(declaring_class_addr, super_class_offset_value,
- irb_.getJObjectTy()->getPointerTo());
-
- llvm::Value* super_class_addr =
- irb_.CreateLoad(super_class_field_addr);
-
- // Load method object from virtual table
- llvm::Value* vtable_addr = EmitLoadVTableAddr(super_class_addr);
-
- llvm::Value* callee_method_object_addr =
- EmitLoadMethodObjectAddrFromVTable(vtable_addr,
- callee_method->GetMethodIndex());
-
-#if 0
- llvm::Value* code_addr =
- EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, false);
-#else
- // TODO: Remove this after we solve the link and trampoline related problems.
- callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr,
- method_object_addr,
- callee_method_idx,
- true);
- EmitGuard_ExceptionLandingPad(dex_pc);
-
- llvm::Value* code_addr = EmitFixStub(callee_method_object_addr,
- callee_method_idx,
- false);
- EmitGuard_ExceptionLandingPad(dex_pc);
-#endif
-
- // Load actual parameters
- std::vector<llvm::Value*> args;
- args.push_back(callee_method_object_addr);
- args.push_back(this_addr);
- EmitLoadActualParameters(args, callee_method_idx, dec_insn,
- is_range, false);
-
- // Invoke callee
- EmitUpdateLineNumFromDexPC(dex_pc);
- llvm::Value* retval = irb_.CreateCall(code_addr, args);
- EmitGuard_ExceptionLandingPad(dex_pc);
-
- MethodHelper method_helper(callee_method);
- char ret_shorty = method_helper.GetShorty()[0];
- if (ret_shorty != 'V') {
- EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval);
- }
- }
-
- irb_.CreateBr(GetNextBasicBlock(dex_pc));
-}
-
-
-void MethodCompiler::EmitInsn_InvokeStaticDirect(uint32_t dex_pc,
- Instruction const* insn,
- InvokeType invoke_type,
- bool is_range) {
-
- DecodedInstruction dec_insn(insn);
-
- uint32_t callee_method_idx = dec_insn.vB;
-
bool is_static = (invoke_type == kStatic);
+ uint32_t callee_method_idx = dec_insn.vB;
- UniquePtr<OatCompilationUnit> callee_oatcompilation_unit(
- oat_compilation_unit_->GetCallee(callee_method_idx, is_static ? kAccStatic : 0));
-
- int vtable_idx = -1; // Currently unused
+ // Compute invoke related information for compiler decision
+ int vtable_idx = -1;
uintptr_t direct_code = 0; // Currently unused
uintptr_t direct_method = 0; // Currently unused
bool is_fast_path = compiler_->
- ComputeInvokeInfo(callee_method_idx, callee_oatcompilation_unit.get(),
+ ComputeInvokeInfo(callee_method_idx, oat_compilation_unit_,
invoke_type, vtable_idx, direct_code, direct_method);
- CHECK(is_fast_path) << "Slow path for invoke static/direct is unimplemented";
-
+ // Load *this* actual parameter
llvm::Value* this_addr = NULL;
if (!is_static) {
// Test: Is *this* parameter equal to null?
- this_addr = EmitLoadCalleeThis(dec_insn, is_range);
+ this_addr = (arg_fmt == kArgReg) ?
+ EmitLoadDalvikReg(dec_insn.arg[0], kObject, kAccurate):
+ EmitLoadDalvikReg(dec_insn.vC + 0, kObject, kAccurate);
+
EmitGuard_NullPointerException(dex_pc, this_addr);
}
- // Load method function pointers
- llvm::Value* callee_method_object_field_addr =
- EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
+ // Load the method object
+ llvm::Value* callee_method_object_addr_ = NULL;
+
+ if (!is_fast_path) {
+ callee_method_object_addr_ =
+ EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx, invoke_type,
+ this_addr, dex_pc, is_fast_path);
+ } else {
+ switch (invoke_type) {
+ case kStatic:
+ case kDirect:
+ callee_method_object_addr_ =
+ EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+ break;
+
+ case kVirtual:
+ DCHECK(vtable_idx != -1);
+ callee_method_object_addr_ =
+ EmitLoadVirtualCalleeMethodObjectAddr(vtable_idx, this_addr);
+ break;
+
+ case kSuper:
+ LOG(FATAL) << "invoke-super should be promoted to invoke-direct in "
+ "the fast path.";
+ break;
+
+ case kInterface:
+ callee_method_object_addr_ =
+ EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx,
+ invoke_type, this_addr,
+ dex_pc, is_fast_path);
+ break;
+ }
+ }
+
+ // Ensure the callee method object is resolved, linked, and its declaring
+ // class is initialized.
+ bool is_virtual = (dec_insn.opcode == Instruction::INVOKE_VIRTUAL) ||
+ (dec_insn.opcode == Instruction::INVOKE_VIRTUAL_RANGE) ||
+ (dec_insn.opcode == Instruction::INVOKE_SUPER) ||
+ (dec_insn.opcode == Instruction::INVOKE_SUPER_RANGE);
+
+ llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr();
llvm::Value* callee_method_object_addr =
- irb_.CreateLoad(callee_method_object_field_addr);
+ EmitEnsureResolved(callee_method_object_addr_,
+ caller_method_object_addr,
+ callee_method_idx,
+ is_virtual);
#if 0
- llvm::Value* code_addr =
- EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, is_static);
-#else
- // TODO: Remove this after we solve the link and trampoline related problems.
- callee_method_object_addr = EmitEnsureResolved(callee_method_object_addr,
- EmitLoadMethodObjectAddr(),
- callee_method_idx,
- false);
- EmitGuard_ExceptionLandingPad(dex_pc);
+ llvm::Value* code_field_offset_value =
+ irb_.getPtrEquivInt(Method::GetCodeOffset().Int32Value());
- llvm::Value* code_addr = EmitFixStub(callee_method_object_addr,
- callee_method_idx,
- is_static);
- EmitGuard_ExceptionLandingPad(dex_pc);
- // FixStub may resolve method, so we need to reload method.
+ llvm::Value* code_field_addr =
+ irb_.CreatePtrDisp(callee_method_object_addr, code_field_offset_value,
+ irb_.getInt8Ty()->getPointerTo()->getPointerTo());
+
+ llvm::Value* code_addr = irb_.CreateLoad(code_field_addr);
+#else
+ // TODO: Remove this after we solve the link and trampoline related problems.
+ llvm::Value* code_addr =
+ EmitFixStub(callee_method_object_addr, callee_method_idx, is_static);
+
+ EmitGuard_ExceptionLandingPad(dex_pc);
#endif
// Load the actual parameter
@@ -3121,18 +2893,23 @@
args.push_back(callee_method_object_addr); // method object for callee
if (!is_static) {
+ DCHECK(this_addr != NULL);
args.push_back(this_addr); // "this" object for callee
}
EmitLoadActualParameters(args, callee_method_idx, dec_insn,
- is_range, is_static);
+ arg_fmt, is_static);
// Invoke callee
EmitUpdateLineNumFromDexPC(dex_pc);
llvm::Value* retval = irb_.CreateCall(code_addr, args);
EmitGuard_ExceptionLandingPad(dex_pc);
- char ret_shorty = callee_oatcompilation_unit->GetShorty()[0];
+ uint32_t callee_access_flags = is_static ? kAccStatic : 0;
+ UniquePtr<OatCompilationUnit> callee_oat_compilation_unit(
+ oat_compilation_unit_->GetCallee(callee_method_idx, callee_access_flags));
+
+ char ret_shorty = callee_oat_compilation_unit->GetShorty()[0];
if (ret_shorty != 'V') {
EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval);
}
@@ -3141,65 +2918,104 @@
}
-void MethodCompiler::EmitInsn_InvokeInterface(uint32_t dex_pc,
- Instruction const* insn,
- bool is_range) {
+llvm::Value* MethodCompiler::
+EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx) {
+ llvm::Value* callee_method_object_field_addr =
+ EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
- DecodedInstruction dec_insn(insn);
+ return irb_.CreateLoad(callee_method_object_field_addr);
+}
- uint32_t callee_method_idx = dec_insn.vB;
- // Resolve callee method
- Method* callee_method = ResolveMethod(callee_method_idx);
+llvm::Value* MethodCompiler::
+EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
+ llvm::Value* this_addr) {
+ // Load class object of *this* pointer
+ llvm::Constant* class_field_offset_value =
+ irb_.getPtrEquivInt(Object::ClassOffset().Int32Value());
- // Test: Is "this" pointer equal to null?
- llvm::Value* this_addr = EmitLoadCalleeThis(dec_insn, is_range);
- EmitGuard_NullPointerException(dex_pc, this_addr);
+ llvm::Value* class_field_addr =
+ irb_.CreatePtrDisp(this_addr, class_field_offset_value,
+ irb_.getJObjectTy()->getPointerTo());
- // Resolve the callee method object address at runtime
- llvm::Value* runtime_func = irb_.GetRuntime(FindInterfaceMethod);
+ llvm::Value* class_object_addr = irb_.CreateLoad(class_field_addr);
- llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+ // Load vtable address
+ llvm::Constant* vtable_offset_value =
+ irb_.getPtrEquivInt(Class::VTableOffset().Int32Value());
+
+ llvm::Value* vtable_field_addr =
+ irb_.CreatePtrDisp(class_object_addr, vtable_offset_value,
+ irb_.getJObjectTy()->getPointerTo());
+
+ llvm::Value* vtable_addr = irb_.CreateLoad(vtable_field_addr);
+
+ // Load callee method object
+ llvm::Value* vtable_idx_value =
+ irb_.getPtrEquivInt(static_cast<uint64_t>(vtable_idx));
+
+ llvm::Value* method_field_addr =
+ EmitArrayGEP(vtable_addr, vtable_idx_value, irb_.getJObjectTy(), kObject);
+
+ return irb_.CreateLoad(method_field_addr);
+}
+
+
+llvm::Value* MethodCompiler::
+EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
+ InvokeType invoke_type,
+ llvm::Value* this_addr,
+ uint32_t dex_pc,
+ bool is_fast_path) {
+
+ llvm::Function* runtime_func = NULL;
+
+ switch (invoke_type) {
+ case kStatic:
+ runtime_func = irb_.GetRuntime(FindStaticMethodWithAccessCheck);
+ break;
+
+ case kDirect:
+ runtime_func = irb_.GetRuntime(FindDirectMethodWithAccessCheck);
+ break;
+
+ case kVirtual:
+ runtime_func = irb_.GetRuntime(FindVirtualMethodWithAccessCheck);
+ break;
+
+ case kSuper:
+ runtime_func = irb_.GetRuntime(FindSuperMethodWithAccessCheck);
+ break;
+
+ case kInterface:
+ if (is_fast_path) {
+ runtime_func = irb_.GetRuntime(FindInterfaceMethod);
+ } else {
+ runtime_func = irb_.GetRuntime(FindInterfaceMethodWithAccessCheck);
+ }
+ break;
+ }
llvm::Value* callee_method_idx_value = irb_.getInt32(callee_method_idx);
+ if (this_addr == NULL) {
+ DCHECK_EQ(invoke_type, kStatic);
+ this_addr = irb_.getJNull();
+ }
+
+ llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr();
+
EmitUpdateLineNumFromDexPC(dex_pc);
llvm::Value* callee_method_object_addr =
irb_.CreateCall3(runtime_func,
- callee_method_idx_value, this_addr, method_object_addr);
+ callee_method_idx_value,
+ this_addr,
+ caller_method_object_addr);
EmitGuard_ExceptionLandingPad(dex_pc);
-#if 0
- llvm::Value* code_addr =
- EmitLoadCodeAddr(callee_method_object_addr, callee_method_idx, false);
-#else
- // TODO: Remove this after we solve the link and trampoline related problems.
- llvm::Value* code_addr = EmitFixStub(callee_method_object_addr,
- callee_method_idx,
- false);
- EmitGuard_ExceptionLandingPad(dex_pc);
-#endif
-
- // Load the actual parameter
- std::vector<llvm::Value*> args;
- args.push_back(callee_method_object_addr);
- args.push_back(this_addr);
- EmitLoadActualParameters(args, callee_method_idx, dec_insn, is_range, false);
-
- // Invoke callee
- EmitUpdateLineNumFromDexPC(dex_pc);
- llvm::Value* retval = irb_.CreateCall(code_addr, args);
- EmitGuard_ExceptionLandingPad(dex_pc);
-
- MethodHelper method_helper(callee_method);
- char ret_shorty = method_helper.GetShorty()[0];
- if (ret_shorty != 'V') {
- EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval);
- }
-
- irb_.CreateBr(GetNextBasicBlock(dex_pc));
+ return callee_method_object_addr;
}
@@ -3712,61 +3528,6 @@
}
-llvm::Value* MethodCompiler::EmitLoadClassObjectAddr(llvm::Value* this_addr) {
- llvm::Constant* class_field_offset_value =
- irb_.getPtrEquivInt(Object::ClassOffset().Int32Value());
-
- llvm::Value* class_field_addr =
- irb_.CreatePtrDisp(this_addr, class_field_offset_value,
- irb_.getJObjectTy()->getPointerTo());
-
- return irb_.CreateLoad(class_field_addr);
-}
-
-
-llvm::Value*
-MethodCompiler::EmitLoadVTableAddr(llvm::Value* class_object_addr) {
- llvm::Constant* vtable_offset_value =
- irb_.getPtrEquivInt(Class::VTableOffset().Int32Value());
-
- llvm::Value* vtable_field_addr =
- irb_.CreatePtrDisp(class_object_addr, vtable_offset_value,
- irb_.getJObjectTy()->getPointerTo());
-
- return irb_.CreateLoad(vtable_field_addr);
-}
-
-
-llvm::Value* MethodCompiler::
-EmitLoadMethodObjectAddrFromVTable(llvm::Value* vtable_addr,
- uint16_t vtable_index) {
- llvm::Value* vtable_index_value =
- irb_.getPtrEquivInt(static_cast<uint64_t>(vtable_index));
-
- llvm::Value* method_field_addr =
- EmitArrayGEP(vtable_addr, vtable_index_value, irb_.getJObjectTy(), kObject);
-
- return irb_.CreateLoad(method_field_addr);
-}
-
-
-llvm::Value* MethodCompiler::EmitLoadCodeAddr(llvm::Value* method_object_addr,
- uint32_t method_idx,
- bool is_static) {
-
- llvm::Value* code_field_offset_value =
- irb_.getPtrEquivInt(Method::GetCodeOffset().Int32Value());
-
- llvm::FunctionType* method_type = GetFunctionType(method_idx, is_static);
-
- llvm::Value* code_field_addr =
- irb_.CreatePtrDisp(method_object_addr, code_field_offset_value,
- method_type->getPointerTo()->getPointerTo());
-
- return irb_.CreateLoad(code_field_addr);
-}
-
-
void MethodCompiler::EmitGuard_NullPointerException(uint32_t dex_pc,
llvm::Value* object) {
llvm::Value* equal_null = irb_.CreateICmpEQ(object, irb_.getJNull());
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index e20a80a..74c55f0 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -129,6 +129,11 @@
kFPArithm_Rem,
};
+ enum InvokeArgFmt {
+ kArgReg,
+ kArgRange,
+ };
+
#define GEN_INSN_ARGS uint32_t dex_pc, Instruction const* insn
// NOP, PAYLOAD (unreachable) instructions
@@ -203,17 +208,20 @@
uint32_t dex_method_idx,
bool is_virtual);
- 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,
- DecodedInstruction &dec_insn,
- bool is_range,
- uint32_t callee_method_idx,
- bool is_virtual);
- void EmitInsn_InvokeStaticDirect(GEN_INSN_ARGS,
- InvokeType invoke_type,
- bool is_range);
- void EmitInsn_InvokeInterface(GEN_INSN_ARGS, bool is_range);
+ void EmitInsn_Invoke(GEN_INSN_ARGS,
+ InvokeType invoke_type,
+ InvokeArgFmt arg_fmt);
+
+ llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx);
+
+ llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
+ llvm::Value* this_addr);
+
+ llvm::Value* EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx,
+ InvokeType invoke_type,
+ llvm::Value* this_addr,
+ uint32_t dex_pc,
+ bool is_fast_path);
// Unary instructions
void EmitInsn_Neg(GEN_INSN_ARGS, JType op_jty);
@@ -338,12 +346,10 @@
llvm::Value* EmitLoadStaticStorage(uint32_t dex_pc, uint32_t type_idx);
- llvm::Value* EmitLoadCalleeThis(DecodedInstruction const& di, bool is_range);
-
void EmitLoadActualParameters(std::vector<llvm::Value*>& args,
uint32_t callee_method_idx,
DecodedInstruction const& di,
- bool is_range,
+ InvokeArgFmt arg_fmt,
bool is_static);
void EmitGuard_DivZeroException(uint32_t dex_pc,
@@ -363,8 +369,6 @@
RegCategory GetInferredRegCategory(uint32_t dex_pc, uint16_t reg);
- Method* ResolveMethod(uint32_t method_idx);
-
Field* ResolveField(uint32_t field_idx);
Field* FindFieldAndDeclaringTypeIdx(uint32_t field_idx,
diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h
index 51cba5b..a271c71 100644
--- a/src/compiler_llvm/runtime_support_func_list.h
+++ b/src/compiler_llvm/runtime_support_func_list.h
@@ -39,9 +39,12 @@
V(AllocArrayWithAccessCheck, art_alloc_array_from_code_with_access_check) \
V(CheckAndAllocArray, art_check_and_alloc_array_from_code) \
V(CheckAndAllocArrayWithAccessCheck, art_check_and_alloc_array_from_code_with_access_check) \
+ V(FindStaticMethodWithAccessCheck, art_find_static_method_from_code_with_access_check) \
+ V(FindDirectMethodWithAccessCheck, art_find_direct_method_from_code_with_access_check) \
+ V(FindVirtualMethodWithAccessCheck, art_find_virtual_method_from_code_with_access_check) \
+ V(FindSuperMethodWithAccessCheck, art_find_super_method_from_code_with_access_check) \
+ V(FindInterfaceMethodWithAccessCheck, art_find_interface_method_from_code_with_access_check) \
V(FindInterfaceMethod, art_find_interface_method_from_code) \
- V(FindVirtualMethod, art_find_virtual_method_from_code) \
- V(FindSuperMethod, art_find_super_method_from_code) \
V(ResolveString, art_resolve_string_from_code) \
V(Set32Static, art_set32_static_from_code) \
V(Set64Static, art_set64_static_from_code) \
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 9c3de0d..c566aea 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -223,24 +223,43 @@
return method;
}
-Object* art_find_interface_method_from_code(uint32_t method_idx,
- Object* this_object,
- Method* referrer) {
- return FindMethodHelper(method_idx, this_object, referrer, true, kInterface);
+Object* art_find_static_method_from_code_with_access_check(uint32_t method_idx,
+ Object* this_object,
+ Method* referrer) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kStatic);
}
-Object* art_find_virtual_method_from_code(uint32_t method_idx,
- Object* this_object,
- Method* referrer) {
+Object* art_find_direct_method_from_code_with_access_check(uint32_t method_idx,
+ Object* this_object,
+ Method* referrer) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kDirect);
+}
+
+Object* art_find_virtual_method_from_code_with_access_check(uint32_t method_idx,
+ Object* this_object,
+ Method* referrer) {
return FindMethodHelper(method_idx, this_object, referrer, true, kVirtual);
}
-Object* art_find_super_method_from_code(uint32_t method_idx,
- Object* this_object,
- Method* referrer) {
+Object* art_find_super_method_from_code_with_access_check(uint32_t method_idx,
+ Object* this_object,
+ Method* referrer) {
return FindMethodHelper(method_idx, this_object, referrer, true, kSuper);
}
+Object*
+art_find_interface_method_from_code_with_access_check(uint32_t method_idx,
+ Object* this_object,
+ Method* referrer) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kInterface);
+}
+
+Object* art_find_interface_method_from_code(uint32_t method_idx,
+ Object* this_object,
+ Method* referrer) {
+ return FindMethodHelper(method_idx, this_object, referrer, false, kInterface);
+}
+
Object* art_initialize_static_storage_from_code(uint32_t type_idx, Method* referrer) {
return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), true, true);
}