diff options
| author | 2012-03-15 21:51:52 -0700 | |
|---|---|---|
| committer | 2012-03-26 20:53:38 -0700 | |
| commit | 28f1a147d77ec772db98bed890b50a9ddcff2365 (patch) | |
| tree | bebca04cea429109260854778da197ae594450d7 /src | |
| parent | 1cb0ae742072b5ea2c7f677e6ad220ba01255dae (diff) | |
Implement LLVM version of jni_compiler to pass 17 jni_compiler tests.
Because we now have both shadow_frame and sirt (which is just for SirtRef<>
in the LLVM version), we define a new function NumStackReferences() as follows:
NumStackReferences() = NumSirtReferences() + NumShadowFrameReferences().
(cherry picked from commit 18fe89a14d212da9ec6841f4d19d08482a9610b7)
Change-Id: Idd95ee4276801b1555be87934cd9c4f33ab8a88a
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_jni.cc | 2 | ||||
| -rw-r--r-- | src/compiler_llvm/art_module.ll | 3 | ||||
| -rw-r--r-- | src/compiler_llvm/generated/art_module.cc | 21 | ||||
| -rw-r--r-- | src/compiler_llvm/jni_compiler.cc | 224 | ||||
| -rw-r--r-- | src/compiler_llvm/jni_compiler.h | 14 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_func_list.h | 3 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_llvm.cc | 7 | ||||
| -rw-r--r-- | src/compiler_llvm/runtime_support_llvm.h | 1 | ||||
| -rw-r--r-- | src/indirect_reference_table.cc | 2 | ||||
| -rw-r--r-- | src/jni_compiler_test.cc | 20 | ||||
| -rw-r--r-- | src/jni_internal.cc | 2 | ||||
| -rw-r--r-- | src/object.h | 2 | ||||
| -rw-r--r-- | src/shadow_frame.h | 10 | ||||
| -rw-r--r-- | src/thread.cc | 24 | ||||
| -rw-r--r-- | src/thread.h | 16 |
15 files changed, 327 insertions, 24 deletions
diff --git a/src/check_jni.cc b/src/check_jni.cc index 3b7c748fe1..cc149354ad 100644 --- a/src/check_jni.cc +++ b/src/check_jni.cc @@ -67,7 +67,7 @@ void JniAbort(const char* jni_function_name) { static bool IsSirtLocalRef(JNIEnv* env, jobject localRef) { return GetIndirectRefKind(localRef) == kSirtOrInvalid && - reinterpret_cast<JNIEnvExt*>(env)->self->SirtContains(localRef); + reinterpret_cast<JNIEnvExt*>(env)->self->StackReferencesContain(localRef); } template<typename T> diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll index 78d388b062..8eb1783bc2 100644 --- a/src/compiler_llvm/art_module.ll +++ b/src/compiler_llvm/art_module.ll @@ -130,6 +130,9 @@ declare %JavaObject* @art_get_obj_instance_from_code(i32, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_decode_jobject_in_thread(%JavaObject*, + %JavaObject*) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; RTTI diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc index fe708ae7b7..18432d5d2e 100644 --- a/src/compiler_llvm/generated/art_module.cc +++ b/src/compiler_llvm/generated/art_module.cc @@ -46,10 +46,10 @@ StructTy_ShadowFrame = StructType::create(mod->getContext(), "ShadowFrame"); 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); } @@ -256,6 +256,14 @@ FunctionType* FuncTy_26 = FunctionType::get( /*Params=*/FuncTy_26_args, /*isVarArg=*/false); +std::vector<Type*>FuncTy_27_args; +FuncTy_27_args.push_back(PointerTy_1); +FuncTy_27_args.push_back(PointerTy_1); +FunctionType* FuncTy_27 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_27_args, + /*isVarArg=*/false); + // Function Declarations @@ -732,6 +740,17 @@ func_art_get_obj_instance_from_code->setCallingConv(CallingConv::C); AttrListPtr func_art_get_obj_instance_from_code_PAL; func_art_get_obj_instance_from_code->setAttributes(func_art_get_obj_instance_from_code_PAL); +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, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_decode_jobject_in_thread", mod); // (external, no body) +func_art_decode_jobject_in_thread->setCallingConv(CallingConv::C); +} +AttrListPtr func_art_decode_jobject_in_thread_PAL; +func_art_decode_jobject_in_thread->setAttributes(func_art_decode_jobject_in_thread_PAL); + 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( diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc index 0e02846b2e..6cccbe182a 100644 --- a/src/compiler_llvm/jni_compiler.cc +++ b/src/compiler_llvm/jni_compiler.cc @@ -26,8 +26,11 @@ #include "oat_compilation_unit.h" #include "object.h" #include "runtime.h" +#include "runtime_support_func.h" #include "utils_llvm.h" +#include <llvm/Analysis/Verifier.h> +#include <llvm/BasicBlock.h> #include <llvm/DerivedTypes.h> #include <llvm/Function.h> #include <llvm/Type.h> @@ -59,8 +62,197 @@ JniCompiler::JniCompiler(CompilationUnit* cunit, CompiledMethod* JniCompiler::Compile() { + bool is_static = method_->IsStatic(); + CreateFunction(); + // Set argument name + llvm::Function::arg_iterator arg_begin(func_->arg_begin()); + llvm::Function::arg_iterator arg_end(func_->arg_end()); + llvm::Function::arg_iterator arg_iter(arg_begin); + + DCHECK_NE(arg_iter, arg_end); + arg_iter->setName("method"); + llvm::Value* method_object_addr = arg_iter++; + + // Actual argument (ignore method) + arg_begin = arg_iter; + + // Count the number of Object* arguments + uint32_t sirt_size = (is_static ? 1 : 0); // Class object for static function + for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) { + arg_iter->setName(StringPrintf("a%u", i)); + if (arg_iter->getType() == irb_.getJObjectTy()) { + ++sirt_size; + } + } + + // Start to build IR + irb_.SetInsertPoint(basic_block_); + + llvm::Value* thread_object_addr = + irb_.CreateCall(irb_.GetRuntime(runtime_support::GetCurrentThread)); + + // Shadow stack + llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size); + shadow_frame_ = irb_.CreateAlloca(shadow_frame_type); + + // Zero-initialization of the shadow frame + llvm::ConstantAggregateZero* zero_initializer = + llvm::ConstantAggregateZero::get(shadow_frame_type); + + irb_.CreateStore(zero_initializer, shadow_frame_); + + // Variables for GetElementPtr + llvm::Constant* zero = irb_.getInt32(0); + llvm::Value* gep_index[] = { + zero, // No displacement for shadow frame pointer + zero, // Get the %ArtFrame data structure + NULL, + }; + + // Store the method pointer + gep_index[2] = irb_.getInt32(2); + llvm::Value* method_field_addr = irb_.CreateGEP(shadow_frame_, gep_index); + irb_.CreateStore(method_object_addr, method_field_addr); + + // Store the number of the pointer slots + gep_index[2] = irb_.getInt32(0); + llvm::Value* size_field_addr = irb_.CreateGEP(shadow_frame_, gep_index); + llvm::ConstantInt* sirt_size_value = irb_.getInt32(sirt_size); + irb_.CreateStore(sirt_size_value, size_field_addr); + + // Push the shadow frame + llvm::Value* shadow_frame_upcast = irb_.CreateConstGEP2_32(shadow_frame_, 0, 0); + irb_.CreateCall(irb_.GetRuntime(runtime_support::PushShadowFrame), shadow_frame_upcast); + + // Set top of managed stack to the method field in the SIRT + StoreToObjectOffset(thread_object_addr, Thread::TopOfManagedStackOffset().Int32Value(), + method_field_addr->getType(), method_field_addr); + + // Get JNIEnv + llvm::Value* jni_env_object_addr = LoadFromObjectOffset(thread_object_addr, + Thread::JniEnvOffset().Int32Value(), + irb_.getJObjectTy()); + + // Set thread state to kNative + StoreToObjectOffset(thread_object_addr, Thread::StateOffset().Int32Value(), + irb_.getInt32Ty(), irb_.getInt32(Thread::kNative)); + + // Get callee code_addr + llvm::Value* code_addr = + LoadFromObjectOffset(method_object_addr, + Method::NativeMethodOffset().Int32Value(), + GetFunctionType(method_idx_, is_static, true)->getPointerTo()); + + + // Load actual parameters + std::vector<llvm::Value*> args; + + args.push_back(jni_env_object_addr); + //args.push_back(method_object_addr); // method object for callee + + // Store arguments to SIRT, and push back to args + gep_index[1] = irb_.getInt32(1); // SIRT + size_t sirt_member_index = 0; + + // Push class argument if this method is static + if (is_static) { + llvm::Value* class_object_addr = + LoadFromObjectOffset(method_object_addr, + Method::DeclaringClassOffset().Int32Value(), + irb_.getJObjectTy()); + gep_index[2] = irb_.getInt32(sirt_member_index++); + llvm::Value* sirt_field_addr = irb_.CreateGEP(shadow_frame_, gep_index); + irb_.CreateStore(class_object_addr, sirt_field_addr); + args.push_back(irb_.CreateBitCast(sirt_field_addr, irb_.getJObjectTy())); + } + for (arg_iter = arg_begin; arg_iter != arg_end; ++arg_iter) { + if (arg_iter->getType() == irb_.getJObjectTy()) { + gep_index[2] = irb_.getInt32(sirt_member_index++); + llvm::Value* sirt_field_addr = irb_.CreateGEP(shadow_frame_, gep_index); + irb_.CreateStore(arg_iter, sirt_field_addr); + // Note null is placed in the SIRT but the jobject passed to the native code must be null + // (not a pointer into the SIRT as with regular references). + llvm::Value* equal_null = irb_.CreateICmpEQ(arg_iter, irb_.getJNull()); + llvm::Value* arg = + irb_.CreateSelect(equal_null, + irb_.getJNull(), + irb_.CreateBitCast(sirt_field_addr, irb_.getJObjectTy())); + args.push_back(arg); + } else { + args.push_back(arg_iter); + } + } + + + // saved_local_ref_cookie = env->local_ref_cookie + llvm::Value* saved_local_ref_cookie = + 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(), + irb_.getInt32Ty(), + segment_state); + + + // Call!!! + llvm::Value* retval = irb_.CreateCall(code_addr, args); + + + // Set thread state to kRunnable + StoreToObjectOffset(thread_object_addr, Thread::StateOffset().Int32Value(), + irb_.getInt32Ty(), irb_.getInt32(Thread::kRunnable)); + + // Get return shorty + DexFile::MethodId const& method_id = dex_file_->GetMethodId(method_idx_); + uint32_t shorty_size; + char ret_shorty = dex_file_->GetMethodShorty(method_id, &shorty_size)[0]; + CHECK_GE(shorty_size, 1u); + + if (ret_shorty == 'L') { + // If the return value is reference, it may point to SIRT, we should decode it. + retval = irb_.CreateCall2(irb_.GetRuntime(runtime_support::DecodeJObjectInThread), + thread_object_addr, retval); + } + + // 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(), + irb_.getInt32Ty(), + local_ref_cookie); + + // env->local_ref_cookie = saved_local_ref_cookie + StoreToObjectOffset(jni_env_object_addr, JNIEnvExt::LocalRefCookieOffset().Int32Value(), + irb_.getInt32Ty(), saved_local_ref_cookie); + + // Pop the shadow frame + irb_.CreateCall(irb_.GetRuntime(runtime_support::PopShadowFrame)); + + // Return! + if (ret_shorty != 'V') { + irb_.CreateRet(retval); + } else { + irb_.CreateRetVoid(); + } + + // For debug + //func_->dump(); + + // Verify the generated bitcode + llvm::verifyFunction(*func_, llvm::PrintMessageAction); + return new CompiledMethod(cunit_->GetInstructionSet(), func_); } @@ -71,16 +263,19 @@ void JniCompiler::CreateFunction() { // Get function type llvm::FunctionType* func_type = - GetFunctionType(method_idx_, method_->IsStatic()); + GetFunctionType(method_idx_, method_->IsStatic(), false); // Create function func_ = llvm::Function::Create(func_type, llvm::Function::ExternalLinkage, func_name, module_); + + // Create basic block + basic_block_ = llvm::BasicBlock::Create(*context_, "B0", func_); } llvm::FunctionType* JniCompiler::GetFunctionType(uint32_t method_idx, - bool is_static) { + bool is_static, bool is_target_function) { // Get method signature DexFile::MethodId const& method_id = dex_file_->GetMethodId(method_idx); @@ -96,8 +291,10 @@ llvm::FunctionType* JniCompiler::GetFunctionType(uint32_t method_idx, args_type.push_back(irb_.getJObjectTy()); // method object pointer - if (!is_static) { - args_type.push_back(irb_.getJType('L', kAccurate)); // "this" object pointer + if (!is_static || is_target_function) { + // "this" object pointer for non-static + // "class" object pointer for static + args_type.push_back(irb_.getJType('L', kAccurate)); } for (uint32_t i = 1; i < shorty_size; ++i) { @@ -107,6 +304,25 @@ 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::Type* type, llvm::Value* 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, type->getPointerTo()); + // Store + irb_.CreateStore(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 a6cdd9c4c8..98129d1251 100644 --- a/src/compiler_llvm/jni_compiler.h +++ b/src/compiler_llvm/jni_compiler.h @@ -33,10 +33,14 @@ namespace art { } namespace llvm { + class AllocaInst; class Function; class FunctionType; + class BasicBlock; class LLVMContext; class Module; + class Type; + class Value; } namespace art { @@ -57,9 +61,14 @@ class JniCompiler { void CreateFunction(); llvm::FunctionType* GetFunctionType(uint32_t method_idx, - bool is_static); + 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::Type* type, llvm::Value* value); + CompilationUnit* cunit_; Compiler const* compiler_; @@ -77,6 +86,9 @@ class JniCompiler { DexFile const* dex_file_; Method* method_; + llvm::BasicBlock* basic_block_; + llvm::AllocaInst* shadow_frame_; + llvm::Function* func_; }; diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h index 01701489ed..38d7a8941f 100644 --- a/src/compiler_llvm/runtime_support_func_list.h +++ b/src/compiler_llvm/runtime_support_func_list.h @@ -54,4 +54,5 @@ V(GetObjectInstance, art_get_obj_instance_from_code) \ 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(FindCatchBlock, art_find_catch_block_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 b6ca288e70..ff4123a622 100644 --- a/src/compiler_llvm/runtime_support_llvm.cc +++ b/src/compiler_llvm/runtime_support_llvm.cc @@ -425,6 +425,12 @@ Object* art_get_obj_instance_from_code(uint32_t field_idx, Method* referrer, Obj return 0; } +Object* art_decode_jobject_in_thread(Thread* thread, jobject obj) { + if (thread->IsExceptionPending()) { + return NULL; + } + return thread->DecodeJObject(obj); +} //---------------------------------------------------------------------------- // RTTI @@ -437,7 +443,6 @@ int32_t art_is_assignable_from_code(Object* dest_type, Object* src_type) { void art_check_cast_from_code(Object* dest_type, Object* src_type) { } - //---------------------------------------------------------------------------- // Runtime Support Function Lookup Callback //---------------------------------------------------------------------------- diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h index 0b38bb7ac4..b93138ab99 100644 --- a/src/compiler_llvm/runtime_support_llvm.h +++ b/src/compiler_llvm/runtime_support_llvm.h @@ -39,7 +39,6 @@ void art_test_suspend_from_code(); void art_set_current_thread_from_code(void* thread_object_addr); - //---------------------------------------------------------------------------- // Runtime Support Function Lookup Callback //---------------------------------------------------------------------------- diff --git a/src/indirect_reference_table.cc b/src/indirect_reference_table.cc index f413236bb8..ac5e402ca9 100644 --- a/src/indirect_reference_table.cc +++ b/src/indirect_reference_table.cc @@ -241,7 +241,7 @@ bool IndirectReferenceTable::Remove(uint32_t cookie, IndirectRef iref) { JavaVMExt* vm = Runtime::Current()->GetJavaVM(); if (GetIndirectRefKind(iref) == kSirtOrInvalid && - Thread::Current()->SirtContains(reinterpret_cast<jobject>(iref))) { + Thread::Current()->StackReferencesContain(reinterpret_cast<jobject>(iref))) { LOG(WARNING) << "Attempt to remove local SIRT entry from IRT, ignoring"; return true; } diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc index 38266c9b71..7a78814c79 100644 --- a/src/jni_compiler_test.cc +++ b/src/jni_compiler_test.cc @@ -106,7 +106,7 @@ jobject JniCompilerTest::jobj_; int gJava_MyClass_foo_calls = 0; void Java_MyClass_foo(JNIEnv* env, jobject thisObj) { // 2 = SirtRef<ClassLoader> + thisObj - EXPECT_EQ(2U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(2U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); @@ -155,7 +155,7 @@ TEST_F(JniCompilerTest, CompileAndRunStaticIntMethodThroughStub) { int gJava_MyClass_fooI_calls = 0; jint Java_MyClass_fooI(JNIEnv* env, jobject thisObj, jint x) { // 2 = SirtRef<ClassLoader> + thisObj - EXPECT_EQ(2U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(2U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); @@ -181,7 +181,7 @@ TEST_F(JniCompilerTest, CompileAndRunIntMethod) { int gJava_MyClass_fooII_calls = 0; jint Java_MyClass_fooII(JNIEnv* env, jobject thisObj, jint x, jint y) { // 2 = SirtRef<ClassLoader> + thisObj - EXPECT_EQ(2U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(2U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); @@ -208,7 +208,7 @@ TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) { int gJava_MyClass_fooJJ_calls = 0; jlong Java_MyClass_fooJJ(JNIEnv* env, jobject thisObj, jlong x, jlong y) { // 2 = SirtRef<ClassLoader> + thisObj - EXPECT_EQ(2U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(2U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); @@ -236,7 +236,7 @@ TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) { int gJava_MyClass_fooDD_calls = 0; jdouble Java_MyClass_fooDD(JNIEnv* env, jobject thisObj, jdouble x, jdouble y) { // 2 = SirtRef<ClassLoader> + thisObj - EXPECT_EQ(2U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(2U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); @@ -266,7 +266,7 @@ int gJava_MyClass_fooIOO_calls = 0; jobject Java_MyClass_fooIOO(JNIEnv* env, jobject thisObj, jint x, jobject y, jobject z) { // 4 = SirtRef<ClassLoader> + this + y + z - EXPECT_EQ(4U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(4U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(thisObj != NULL); @@ -317,7 +317,7 @@ TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) { int gJava_MyClass_fooSII_calls = 0; jint Java_MyClass_fooSII(JNIEnv* env, jclass klass, jint x, jint y) { // 2 = SirtRef<ClassLoader> + klass - EXPECT_EQ(2U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(2U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); @@ -340,7 +340,7 @@ TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) { int gJava_MyClass_fooSDD_calls = 0; jdouble Java_MyClass_fooSDD(JNIEnv* env, jclass klass, jdouble x, jdouble y) { // 2 = SirtRef<ClassLoader> + klass - EXPECT_EQ(2U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(2U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); @@ -369,7 +369,7 @@ int gJava_MyClass_fooSIOO_calls = 0; jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y, jobject z) { // 4 = SirtRef<ClassLoader> + klass + y + z - EXPECT_EQ(4U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(4U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); @@ -422,7 +422,7 @@ int gJava_MyClass_fooSSIOO_calls = 0; jobject Java_MyClass_fooSSIOO(JNIEnv* env, jclass klass, jint x, jobject y, jobject z) { // 4 = SirtRef<ClassLoader> + klass + y + z - EXPECT_EQ(4U, Thread::Current()->NumSirtReferences()); + EXPECT_EQ(4U, Thread::Current()->NumStackReferences()); EXPECT_EQ(Thread::kNative, Thread::Current()->GetState()); EXPECT_EQ(Thread::Current()->GetJniEnv(), env); EXPECT_TRUE(klass != NULL); diff --git a/src/jni_internal.cc b/src/jni_internal.cc index f0943a7be7..00667adb38 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -2300,7 +2300,7 @@ class JNI { return JNIWeakGlobalRefType; case kSirtOrInvalid: // Is it in a stack IRT? - if (ts.Self()->SirtContains(java_object)) { + if (ts.Self()->StackReferencesContain(java_object)) { return JNILocalRefType; } diff --git a/src/object.h b/src/object.h index c58eb29e65..7ba084768f 100644 --- a/src/object.h +++ b/src/object.h @@ -774,7 +774,9 @@ class MANAGED Method : public Object { size_t GetFrameSizeInBytes() const { DCHECK_EQ(sizeof(size_t), sizeof(uint32_t)); size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_), false); +#if !defined(ART_USE_LLVM_COMPILER) // LLVM uses shadow stack instead. DCHECK_LE(static_cast<size_t>(kStackAlignment), result); +#endif return result; } diff --git a/src/shadow_frame.h b/src/shadow_frame.h index 3bdee8e443..c5b6492c43 100644 --- a/src/shadow_frame.h +++ b/src/shadow_frame.h @@ -51,6 +51,16 @@ class ShadowFrame { references_[i] = object; } + bool Contains(Object** shadow_frame_entry) const { + // A ShadowFrame should at least contain a reference. Even if a + // native method has no argument, we put jobject or jclass as a + // reference. The former is "this", while the latter is for static + // method. + DCHECK_GT(number_of_references_, 0U); + return ((&references_[0] <= shadow_frame_entry) + && (shadow_frame_entry <= (&references_[number_of_references_ - 1]))); + } + // Offset of link within shadow frame static size_t LinkOffset() { return OFFSETOF_MEMBER(ShadowFrame, link_); diff --git a/src/thread.cc b/src/thread.cc index f3e1092726..6b340d2784 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -1072,6 +1072,14 @@ size_t Thread::NumSirtReferences() { return count; } +size_t Thread::NumShadowFrameReferences() { + size_t count = 0; + for (ShadowFrame* cur = top_shadow_frame_; cur; cur = cur->GetLink()) { + count += cur->NumberOfReferences(); + } + return count; +} + bool Thread::SirtContains(jobject obj) { Object** sirt_entry = reinterpret_cast<Object**>(obj); for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->GetLink()) { @@ -1082,6 +1090,20 @@ bool Thread::SirtContains(jobject obj) { return false; } +bool Thread::ShadowFrameContains(jobject obj) { + Object** shadow_frame_entry = reinterpret_cast<Object**>(obj); + for (ShadowFrame* cur = top_shadow_frame_; cur; cur = cur->GetLink()) { + if (cur->Contains(shadow_frame_entry)) { + return true; + } + } + return false; +} + +bool Thread::StackReferencesContain(jobject obj) { + return SirtContains(obj) || ShadowFrameContains(obj); +} + void Thread::SirtVisitRoots(Heap::RootVisitor* visitor, void* arg) { for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->GetLink()) { size_t num_refs = cur->NumberOfReferences(); @@ -1145,7 +1167,7 @@ Object* Thread::DecodeJObject(jobject obj) { default: // TODO: make stack indirect reference table lookup more efficient // Check if this is a local reference in the SIRT - if (SirtContains(obj)) { + if (StackReferencesContain(obj)) { result = *reinterpret_cast<Object**>(obj); // Read from SIRT } else if (Runtime::Current()->GetJavaVM()->work_around_app_jni_bugs) { // Assume an invalid local reference is actually a direct pointer. diff --git a/src/thread.h b/src/thread.h index 6f91b31980..6c29af26be 100644 --- a/src/thread.h +++ b/src/thread.h @@ -265,12 +265,26 @@ class PACKED Thread { return jni_env_; } - // Number of references allocated in SIRTs on this thread + // Number of references in SIRTs on this thread size_t NumSirtReferences(); + // Number of references allocated in ShadowFrames on this thread + size_t NumShadowFrameReferences(); + + // Number of references allocated in SIRTs & shadow frames on this thread + size_t NumStackReferences() { + return NumSirtReferences() + NumShadowFrameReferences(); + }; + // Is the given obj in this thread's stack indirect reference table? bool SirtContains(jobject obj); + // Is the given obj in this thread's ShadowFrame? + bool ShadowFrameContains(jobject obj); + + // Is the given obj in this thread's Sirts & ShadowFrames? + bool StackReferencesContain(jobject obj); + void SirtVisitRoots(Heap::RootVisitor* visitor, void* arg); void ShadowFrameVisitRoots(Heap::RootVisitor* visitor, void* arg); |