diff options
| author | 2012-04-11 05:57:28 -0700 | |
|---|---|---|
| committer | 2012-04-11 11:01:21 -0700 | |
| commit | 5bb8601175bbb9cd761c715f4ba04f84d65e913b (patch) | |
| tree | 441c62e467b6c7a355d9ad65ea88a923abbb409b /src/compiler_llvm | |
| parent | 933abf8ce64e522b1c45b191b796bf2208a760d9 (diff) | |
Fix 044-proxy. Implement proxy for now, working on x86 and ARM.
Already added a TODO to do the assembly code for x86 and ARM for proxy.
Use LLVM .ll for multi-architecture now.
Change-Id: Ibdeeee113dcf284592e9d7769d3044438cb1e453
Diffstat (limited to 'src/compiler_llvm')
| -rw-r--r-- | src/compiler_llvm/art_module.ll | 2 | ||||
| -rw-r--r-- | src/compiler_llvm/generated/art_module.cc | 18 | ||||
| -rw-r--r-- | src/compiler_llvm/ir_builder.h | 20 | ||||
| -rw-r--r-- | src/compiler_llvm/jni_compiler.cc | 103 | ||||
| -rw-r--r-- | src/compiler_llvm/jni_compiler.h | 4 | ||||
| -rw-r--r-- | src/compiler_llvm/method_compiler.cc | 68 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_func_list.h | 1 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_llvm.cc | 154 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_llvm.h | 10 |
9 files changed, 313 insertions, 67 deletions
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll index 9354bb6f9a..a5de7a3360 100644 --- a/src/compiler_llvm/art_module.ll +++ b/src/compiler_llvm/art_module.ll @@ -158,3 +158,5 @@ declare %JavaObject* @art_ensure_resolved_from_code(%JavaObject*, i1) declare %JavaObject* @art_fix_stub_from_code(%JavaObject*) + +declare void @art_proxy_invoke_handler_from_code(%JavaObject*, ...) diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc index 6889ed965c..cdde019265 100644 --- a/src/compiler_llvm/generated/art_module.cc +++ b/src/compiler_llvm/generated/art_module.cc @@ -290,6 +290,13 @@ FunctionType* FuncTy_30 = FunctionType::get( /*Params=*/FuncTy_30_args, /*isVarArg=*/false); +std::vector<Type*>FuncTy_31_args; +FuncTy_31_args.push_back(PointerTy_1); +FunctionType* FuncTy_31 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_31_args, + /*isVarArg=*/true); + // Function Declarations @@ -876,6 +883,17 @@ func_art_fix_stub_from_code->setCallingConv(CallingConv::C); AttrListPtr func_art_fix_stub_from_code_PAL; func_art_fix_stub_from_code->setAttributes(func_art_fix_stub_from_code_PAL); +Function* func_art_proxy_invoke_handler_from_code = mod->getFunction("art_proxy_invoke_handler_from_code"); +if (!func_art_proxy_invoke_handler_from_code) { +func_art_proxy_invoke_handler_from_code = Function::Create( + /*Type=*/FuncTy_31, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_proxy_invoke_handler_from_code", mod); // (external, no body) +func_art_proxy_invoke_handler_from_code->setCallingConv(CallingConv::C); +} +AttrListPtr func_art_proxy_invoke_handler_from_code_PAL; +func_art_proxy_invoke_handler_from_code->setAttributes(func_art_proxy_invoke_handler_from_code_PAL); + // Global Variable Declarations diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h index 0762a0dd89..d199b76604 100644 --- a/src/compiler_llvm/ir_builder.h +++ b/src/compiler_llvm/ir_builder.h @@ -89,6 +89,26 @@ class IRBuilder : public LLVMIRBuilder { return CreatePtrDisp(base, total_offset, ret_ty); } + llvm::Value* LoadFromObjectOffset(llvm::Value* object_addr, int32_t offset, llvm::Type* type) { + // Convert offset to llvm::value + llvm::Value* llvm_offset = getPtrEquivInt(offset); + // Calculate the value's address + llvm::Value* value_addr = CreatePtrDisp(object_addr, llvm_offset, type->getPointerTo()); + // Load + return CreateLoad(value_addr); + } + + void StoreToObjectOffset(llvm::Value* object_addr, int32_t offset, llvm::Value* new_value) { + // Convert offset to llvm::value + llvm::Value* llvm_offset = getPtrEquivInt(offset); + // Calculate the value's address + llvm::Value* value_addr = CreatePtrDisp(object_addr, + llvm_offset, + new_value->getType()->getPointerTo()); + // Store + CreateStore(new_value, value_addr); + } + //-------------------------------------------------------------------------- // Runtime Helper Function diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc index 252daef685..68ce2d88b5 100644 --- a/src/compiler_llvm/jni_compiler.cc +++ b/src/compiler_llvm/jni_compiler.cc @@ -88,9 +88,9 @@ CompiledMethod* JniCompiler::Compile() { } else { // Load class object this_object_or_class_object = - LoadFromObjectOffset(method_object_addr, - Method::DeclaringClassOffset().Int32Value(), - irb_.getJObjectTy()); + irb_.LoadFromObjectOffset(method_object_addr, + Method::DeclaringClassOffset().Int32Value(), + irb_.getJObjectTy()); } // Actual argument (ignore method and this object) arg_begin = arg_iter; @@ -126,34 +126,35 @@ CompiledMethod* JniCompiler::Compile() { irb_.CreateStore(method_object_addr, method_field_addr); // Store the line number - StoreToObjectOffset(shadow_frame_, - ShadowFrame::LineNumOffset(), - irb_.getInt32(dex_file_->GetLineNumFromPC(method_, 0))); + irb_.StoreToObjectOffset(shadow_frame_, + ShadowFrame::LineNumOffset(), + irb_.getInt32(dex_file_->GetLineNumFromPC(method_, 0))); // Store the number of the pointer slots - StoreToObjectOffset(shadow_frame_, - ShadowFrame::NumberOfReferencesOffset(), - irb_.getInt32(sirt_size)); + irb_.StoreToObjectOffset(shadow_frame_, + ShadowFrame::NumberOfReferencesOffset(), + irb_.getInt32(sirt_size)); // Push the shadow frame llvm::Value* shadow_frame_upcast = irb_.CreateConstGEP2_32(shadow_frame_, 0, 0); irb_.CreateCall(irb_.GetRuntime(PushShadowFrame), shadow_frame_upcast); // Get JNIEnv - llvm::Value* jni_env_object_addr = LoadFromObjectOffset(thread_object_addr, - Thread::JniEnvOffset().Int32Value(), - irb_.getJObjectTy()); + llvm::Value* jni_env_object_addr = + irb_.LoadFromObjectOffset(thread_object_addr, + Thread::JniEnvOffset().Int32Value(), + irb_.getJObjectTy()); // Set thread state to kNative - StoreToObjectOffset(thread_object_addr, - Thread::StateOffset().Int32Value(), - irb_.getInt32(kNative)); + irb_.StoreToObjectOffset(thread_object_addr, + Thread::StateOffset().Int32Value(), + irb_.getInt32(kNative)); // Get callee code_addr llvm::Value* code_addr = - LoadFromObjectOffset(method_object_addr, - Method::NativeMethodOffset().Int32Value(), - GetFunctionType(method_idx_, is_static, true)->getPointerTo()); + irb_.LoadFromObjectOffset(method_object_addr, + Method::NativeMethodOffset().Int32Value(), + GetFunctionType(method_idx_, is_static, true)->getPointerTo()); // Load actual parameters std::vector<llvm::Value*> args; @@ -230,18 +231,18 @@ CompiledMethod* JniCompiler::Compile() { // saved_local_ref_cookie = env->local_ref_cookie llvm::Value* saved_local_ref_cookie = - LoadFromObjectOffset(jni_env_object_addr, - JNIEnvExt::LocalRefCookieOffset().Int32Value(), - irb_.getInt32Ty()); + irb_.LoadFromObjectOffset(jni_env_object_addr, + JNIEnvExt::LocalRefCookieOffset().Int32Value(), + irb_.getInt32Ty()); // env->local_ref_cookie = env->locals.segment_state llvm::Value* segment_state = - LoadFromObjectOffset(jni_env_object_addr, - JNIEnvExt::SegmentStateOffset().Int32Value(), - irb_.getInt32Ty()); - StoreToObjectOffset(jni_env_object_addr, - JNIEnvExt::LocalRefCookieOffset().Int32Value(), - segment_state); + irb_.LoadFromObjectOffset(jni_env_object_addr, + JNIEnvExt::SegmentStateOffset().Int32Value(), + irb_.getInt32Ty()); + irb_.StoreToObjectOffset(jni_env_object_addr, + JNIEnvExt::LocalRefCookieOffset().Int32Value(), + segment_state); // Call!!! @@ -254,9 +255,9 @@ CompiledMethod* JniCompiler::Compile() { } // Set thread state to kRunnable - StoreToObjectOffset(thread_object_addr, - Thread::StateOffset().Int32Value(), - irb_.getInt32(kRunnable)); + irb_.StoreToObjectOffset(thread_object_addr, + Thread::StateOffset().Int32Value(), + irb_.getInt32(kRunnable)); if (return_shorty == 'L') { // If the return value is reference, it may point to SIRT, we should decode it. @@ -267,17 +268,17 @@ CompiledMethod* JniCompiler::Compile() { // env->locals.segment_state = env->local_ref_cookie llvm::Value* local_ref_cookie = - LoadFromObjectOffset(jni_env_object_addr, - JNIEnvExt::LocalRefCookieOffset().Int32Value(), - irb_.getInt32Ty()); - StoreToObjectOffset(jni_env_object_addr, - JNIEnvExt::SegmentStateOffset().Int32Value(), - local_ref_cookie); + irb_.LoadFromObjectOffset(jni_env_object_addr, + JNIEnvExt::LocalRefCookieOffset().Int32Value(), + irb_.getInt32Ty()); + irb_.StoreToObjectOffset(jni_env_object_addr, + JNIEnvExt::SegmentStateOffset().Int32Value(), + local_ref_cookie); // env->local_ref_cookie = saved_local_ref_cookie - StoreToObjectOffset(jni_env_object_addr, - JNIEnvExt::LocalRefCookieOffset().Int32Value(), - saved_local_ref_cookie); + irb_.StoreToObjectOffset(jni_env_object_addr, + JNIEnvExt::LocalRefCookieOffset().Int32Value(), + saved_local_ref_cookie); // Pop the shadow frame irb_.CreateCall(irb_.GetRuntime(PopShadowFrame)); @@ -348,29 +349,5 @@ llvm::FunctionType* JniCompiler::GetFunctionType(uint32_t method_idx, return llvm::FunctionType::get(ret_type, args_type, false); } -llvm::Value* JniCompiler::LoadFromObjectOffset(llvm::Value* object_addr, - int32_t offset, - llvm::Type* type) { - // Convert offset to llvm::value - llvm::Value* llvm_offset = irb_.getPtrEquivInt(offset); - // Calculate the value's address - llvm::Value* value_addr = irb_.CreatePtrDisp(object_addr, llvm_offset, type->getPointerTo()); - // Load - return irb_.CreateLoad(value_addr); -} - -void JniCompiler::StoreToObjectOffset(llvm::Value* object_addr, - int32_t offset, - llvm::Value* new_value) { - // Convert offset to llvm::value - llvm::Value* llvm_offset = irb_.getPtrEquivInt(offset); - // Calculate the value's address - llvm::Value* value_addr = irb_.CreatePtrDisp(object_addr, - llvm_offset, - new_value->getType()->getPointerTo()); - // Store - irb_.CreateStore(new_value, value_addr); -} - } // namespace compiler_llvm } // namespace art diff --git a/src/compiler_llvm/jni_compiler.h b/src/compiler_llvm/jni_compiler.h index d91293de7a..15a789c64f 100644 --- a/src/compiler_llvm/jni_compiler.h +++ b/src/compiler_llvm/jni_compiler.h @@ -62,10 +62,6 @@ class JniCompiler { bool is_static, bool is_target_function); private: - llvm::Value* LoadFromObjectOffset(llvm::Value* object_addr, int32_t offset, llvm::Type* type); - - void StoreToObjectOffset(llvm::Value* object_addr, int32_t offset, llvm::Value* new_value); - CompilationUnit* cunit_; Compiler const* compiler_; diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc index 50ed471ed5..fb6cc19343 100644 --- a/src/compiler_llvm/method_compiler.cc +++ b/src/compiler_llvm/method_compiler.cc @@ -27,6 +27,7 @@ #include "object.h" #include "object_utils.h" #include "runtime_support_func.h" +#include "runtime_support_llvm.h" #include "shadow_frame.h" #include "stl_util.h" #include "stringprintf.h" @@ -2884,6 +2885,7 @@ void MethodCompiler::EmitInsn_Invoke(uint32_t dex_pc, EmitLoadActualParameters(args, callee_method_idx, dec_insn, arg_fmt, is_static); +#if 0 // Invoke callee EmitUpdateLineNumFromDexPC(dex_pc); llvm::Value* retval = irb_.CreateCall(code_addr, args); @@ -2897,6 +2899,72 @@ void MethodCompiler::EmitInsn_Invoke(uint32_t dex_pc, if (ret_shorty != 'V') { EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval); } +#else + 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]; + + + EmitUpdateLineNumFromDexPC(dex_pc); + + + llvm::BasicBlock* block_normal = CreateBasicBlockWithDexPC(dex_pc, "normal"); + llvm::BasicBlock* block_proxy_stub = CreateBasicBlockWithDexPC(dex_pc, "proxy"); + llvm::BasicBlock* block_continue = CreateBasicBlockWithDexPC(dex_pc, "cont"); + + llvm::Type* accurate_ret_type = irb_.getJType(ret_shorty, kAccurate); + llvm::Value* retval_addr = NULL; + if (ret_shorty != 'V') { + retval_addr = irb_.CreateAlloca(accurate_ret_type); + } + + + // TODO: Remove this after we solve the proxy trampoline calling convention problem. + llvm::Value* code_addr_int = irb_.CreatePtrToInt(code_addr, irb_.getPtrEquivIntTy()); + llvm::Value* proxy_stub_int = irb_.getPtrEquivInt(special_stub::kProxyStub); + llvm::Value* is_proxy_stub = irb_.CreateICmpEQ(code_addr_int, proxy_stub_int); + irb_.CreateCondBr(is_proxy_stub, block_proxy_stub, block_normal); + + + irb_.SetInsertPoint(block_normal); + { + // Invoke callee + llvm::Value* result = irb_.CreateCall(code_addr, args); + if (ret_shorty != 'V') { + irb_.CreateStore(result, retval_addr); + } + } + irb_.CreateBr(block_continue); + + + irb_.SetInsertPoint(block_proxy_stub); + { + llvm::Value* temp_space_addr; + if (ret_shorty != 'V') { + temp_space_addr = irb_.CreateAlloca(irb_.getJValueTy()); + args.push_back(temp_space_addr); + } + irb_.CreateCall(irb_.GetRuntime(ProxyInvokeHandler), args); + if (ret_shorty != 'V') { + llvm::Value* result_addr = + irb_.CreateBitCast(temp_space_addr, accurate_ret_type->getPointerTo()); + llvm::Value* retval = irb_.CreateLoad(result_addr); + irb_.CreateStore(retval, retval_addr); + } + } + irb_.CreateBr(block_continue); + + + irb_.SetInsertPoint(block_continue); + + if (ret_shorty != 'V') { + llvm::Value* retval = irb_.CreateLoad(retval_addr); + EmitStoreDalvikRetValReg(ret_shorty, kAccurate, retval); + } + EmitGuard_ExceptionLandingPad(dex_pc); +#endif irb_.CreateBr(GetNextBasicBlock(dex_pc)); } diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h index a271c71bc0..0e58e9c71a 100644 --- a/src/compiler_llvm/runtime_support_func_list.h +++ b/src/compiler_llvm/runtime_support_func_list.h @@ -63,4 +63,5 @@ V(FindCatchBlock, art_find_catch_block_from_code) \ V(EnsureResolved, art_ensure_resolved_from_code) \ V(FixStub, art_fix_stub_from_code) \ + V(ProxyInvokeHandler, art_proxy_invoke_handler_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 c566aea120..d354bee9cc 100644 --- a/src/compiler_llvm/runtime_support_llvm.cc +++ b/src/compiler_llvm/runtime_support_llvm.cc @@ -19,13 +19,16 @@ #include "nth_caller_visitor.h" #include "object.h" #include "object_utils.h" +#include "reflection.h" #include "runtime_support.h" #include "runtime_support_llvm.h" +#include "ScopedLocalRef.h" #include "shadow_frame.h" #include "thread.h" #include "thread_list.h" #include <algorithm> +#include <cstdarg> #include <stdint.h> namespace art { @@ -629,6 +632,157 @@ const void* art_fix_stub_from_code(Method* called) { return code; } +// Handler for invocation on proxy methods. We create a boxed argument array. And we invoke +// the invocation handler which is a field within the proxy object receiver. +void art_proxy_invoke_handler_from_code(Method* proxy_method, ...) { + va_list ap; + va_start(ap, proxy_method); + + Object* receiver = va_arg(ap, Object*); + Thread* thread = Thread::Current(); + MethodHelper proxy_mh(proxy_method); + const size_t num_params = proxy_mh.NumArgs(); + + // Start new JNI local reference state + JNIEnvExt* env = thread->GetJniEnv(); + ScopedJniEnvLocalRefState env_state(env); + + // Create local ref. copies of proxy method and the receiver + jobject rcvr_jobj = AddLocalReference<jobject>(env, receiver); + + // Convert proxy method into expected interface method + Method* interface_method = proxy_method->FindOverriddenMethod(); + DCHECK(interface_method != NULL); + DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); + + // Set up arguments array and place in local IRT during boxing (which may allocate/GC) + jvalue args_jobj[3]; + args_jobj[0].l = rcvr_jobj; + args_jobj[1].l = AddLocalReference<jobject>(env, interface_method); + // Args array, if no arguments then NULL (don't include receiver in argument count) + args_jobj[2].l = NULL; + ObjectArray<Object>* args = NULL; + if ((num_params - 1) > 0) { + args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1); + if (args == NULL) { + CHECK(thread->IsExceptionPending()); + return; + } + args_jobj[2].l = AddLocalReference<jobjectArray>(env, args); + } + + // Get parameter types. + const char* shorty = proxy_mh.GetShorty(); + ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes(); + if (param_types == NULL) { + CHECK(thread->IsExceptionPending()); + return; + } + + // Box arguments. + for (size_t i = 0; i < (num_params - 1);++i) { + JValue val; + switch (shorty[i+1]) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + case 'F': + val.i = va_arg(ap, jint); + break; + case 'L': + val.l = va_arg(ap, Object*); + break; + case 'D': + case 'J': + val.j = va_arg(ap, jlong); + break; + } + Class* param_type = param_types->Get(i); + if (param_type->IsPrimitive()) { + BoxPrimitive(param_type->GetPrimitiveType(), val); + if (thread->IsExceptionPending()) { + return; + } + } + args->Set(i, val.l); + } + + // Get the InvocationHandler method and the field that holds it within the Proxy object + static jmethodID inv_hand_invoke_mid = NULL; + static jfieldID proxy_inv_hand_fid = NULL; + if (proxy_inv_hand_fid == NULL) { + ScopedLocalRef<jclass> proxy(env, env->FindClass("java/lang/reflect/Proxy")); + proxy_inv_hand_fid = env->GetFieldID(proxy.get(), "h", "Ljava/lang/reflect/InvocationHandler;"); + ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java/lang/reflect/InvocationHandler")); + inv_hand_invoke_mid = env->GetMethodID(inv_hand_class.get(), "invoke", + "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); + } + + DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java/lang/reflect/Proxy"))); + + jobject inv_hand = env->GetObjectField(rcvr_jobj, proxy_inv_hand_fid); + // Call InvocationHandler.invoke + jobject result = env->CallObjectMethodA(inv_hand, inv_hand_invoke_mid, args_jobj); + + // Place result in stack args + if (!thread->IsExceptionPending()) { + if (shorty[0] == 'V') { + return; + } + Object* result_ref = thread->DecodeJObject(result); + JValue* result_unboxed = va_arg(ap, JValue*); + if (result_ref == NULL) { + result_unboxed->l = NULL; + } else { + bool unboxed_okay = UnboxPrimitive(result_ref, proxy_mh.GetReturnType(), *result_unboxed, "result"); + if (!unboxed_okay) { + thread->ClearException(); + thread->ThrowNewExceptionF("Ljava/lang/ClassCastException;", + "Couldn't convert result of type %s to %s", + PrettyTypeOf(result_ref).c_str(), + PrettyDescriptor(proxy_mh.GetReturnType()).c_str()); + return; + } + } + } else { + // In the case of checked exceptions that aren't declared, the exception must be wrapped by + // a UndeclaredThrowableException. + Throwable* exception = thread->GetException(); + thread->ClearException(); + if (!exception->IsCheckedException()) { + thread->SetException(exception); + } else { + SynthesizedProxyClass* proxy_class = + down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass()); + int throws_index = -1; + size_t num_virt_methods = proxy_class->NumVirtualMethods(); + for (size_t i = 0; i < num_virt_methods; i++) { + if (proxy_class->GetVirtualMethod(i) == proxy_method) { + throws_index = i; + break; + } + } + CHECK_NE(throws_index, -1); + ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index); + Class* exception_class = exception->GetClass(); + bool declares_exception = false; + for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) { + Class* declared_exception = declared_exceptions->Get(i); + declares_exception = declared_exception->IsAssignableFrom(exception_class); + } + if (declares_exception) { + thread->SetException(exception); + } else { + ThrowNewUndeclaredThrowableException(thread, env, exception); + } + } + } + + va_end(ap); +} + 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 ab5c8047d3..112025188a 100644 --- a/src/compiler_llvm/runtime_support_llvm.h +++ b/src/compiler_llvm/runtime_support_llvm.h @@ -19,6 +19,16 @@ namespace art { +namespace compiler_llvm { +namespace special_stub { + enum SpecialStub { + kProxyStub = 16, + kMaxSpecialStub + }; +} +} // namespace compiler_llvm + + class Method; class Object; |