diff options
| author | 2012-04-11 05:57:28 -0700 | |
|---|---|---|
| committer | 2012-04-11 11:01:21 -0700 | |
| commit | 5bb8601175bbb9cd761c715f4ba04f84d65e913b (patch) | |
| tree | 441c62e467b6c7a355d9ad65ea88a923abbb409b | |
| 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
| -rw-r--r-- | src/class_linker.cc | 13 | ||||
| -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 | ||||
| -rw-r--r-- | src/oat/runtime/support_proxy.cc | 21 | ||||
| -rw-r--r-- | src/runtime_support.cc | 22 | ||||
| -rw-r--r-- | src/runtime_support.h | 2 |
13 files changed, 351 insertions, 87 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc index 08792ebd4f..b94003aaa5 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -43,6 +43,9 @@ #include "os.h" #include "runtime.h" #include "runtime_support.h" +#if defined(ART_USE_LLVM_COMPILER) +#include "compiler_llvm/runtime_support_llvm.h" +#endif #include "ScopedLocalRef.h" #include "space.h" #include "stack_indirect_reference_table.h" @@ -2299,6 +2302,11 @@ Method* ClassLinker::CreateProxyConstructor(SirtRef<Class>& klass, Class* proxy_ ObjectArray<Method>* proxy_direct_methods = proxy_class->GetDirectMethods(); CHECK_EQ(proxy_direct_methods->GetLength(), 15); Method* proxy_constructor = proxy_direct_methods->Get(2); +#if defined(ART_USE_LLVM_COMPILER) + // Ensure link. + // TODO: Remove this after fixing the link problem by in-place linking. + art_fix_stub_from_code(proxy_constructor); +#endif // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its // code_ too) Method* constructor = down_cast<Method*>(proxy_constructor->Clone()); @@ -2336,7 +2344,12 @@ Method* ClassLinker::CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& p method->SetCoreSpillMask(refs_and_args->GetCoreSpillMask()); method->SetFpSpillMask(refs_and_args->GetFpSpillMask()); method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes()); +#if !defined(ART_USE_LLVM_COMPILER) method->SetCode(reinterpret_cast<void*>(art_proxy_invoke_handler)); +#else + method->SetCode(reinterpret_cast<const void*>( + static_cast<uintptr_t>(compiler_llvm::special_stub::kProxyStub))); +#endif return method; } 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; diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc index dd92fb19f5..25cafc2961 100644 --- a/src/oat/runtime/support_proxy.cc +++ b/src/oat/runtime/support_proxy.cc @@ -17,32 +17,13 @@ #include "object.h" #include "object_utils.h" #include "reflection.h" +#include "runtime_support.h" #include "thread.h" #include "ScopedLocalRef.h" namespace art { -static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) { - ScopedLocalRef<jclass> jlr_UTE_class(env, - env->FindClass("java/lang/reflect/UndeclaredThrowableException")); - if (jlr_UTE_class.get() == NULL) { - LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\""; - } else { - jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>", - "(Ljava/lang/Throwable;)V"); - jthrowable jexception = AddLocalReference<jthrowable>(env, exception); - ScopedLocalRef<jthrowable> jlr_UTE(env, - reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), jlre_UTE_constructor, - jexception))); - int rc = env->Throw(jlr_UTE.get()); - if (rc != JNI_OK) { - LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\""; - } - } - CHECK(self->IsExceptionPending()); -} - // Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method // which is responsible for recording callee save registers. We explicitly handlerize incoming // reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke diff --git a/src/runtime_support.cc b/src/runtime_support.cc index d6efe1d7ea..38a680e7a7 100644 --- a/src/runtime_support.cc +++ b/src/runtime_support.cc @@ -16,6 +16,8 @@ #include "runtime_support.h" +#include "ScopedLocalRef.h" + namespace art { void ThrowNewIllegalAccessErrorClass(Thread* self, @@ -529,4 +531,24 @@ Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* return klass; } +void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) { + ScopedLocalRef<jclass> jlr_UTE_class(env, + env->FindClass("java/lang/reflect/UndeclaredThrowableException")); + if (jlr_UTE_class.get() == NULL) { + LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\""; + } else { + jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>", + "(Ljava/lang/Throwable;)V"); + jthrowable jexception = AddLocalReference<jthrowable>(env, exception); + ScopedLocalRef<jthrowable> jlr_UTE(env, + reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), jlre_UTE_constructor, + jexception))); + int rc = env->Throw(jlr_UTE.get()); + if (rc != JNI_OK) { + LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\""; + } + } + CHECK(self->IsExceptionPending()); +} + } // namespace art diff --git a/src/runtime_support.h b/src/runtime_support.h index bbb9512c92..673a535ec2 100644 --- a/src/runtime_support.h +++ b/src/runtime_support.h @@ -207,6 +207,8 @@ static inline String* ResolveStringFromCode(const Method* referrer, uint32_t str return class_linker->ResolveString(string_idx, referrer); } +extern void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception); + } // namespace art #endif // ART_SRC_RUNTIME_SUPPORT_H_ |