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
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 3b7c748..cc14935 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -67,7 +67,7 @@
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 78d388b..8eb1783 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -130,6 +130,9 @@
%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 fe708ae..18432d5 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -46,10 +46,10 @@
std::vector<Type*>StructTy_ShadowFrame_fields;
PointerType* PointerTy_2 = PointerType::get(StructTy_ShadowFrame, 0);
+StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
StructTy_ShadowFrame_fields.push_back(PointerTy_2);
StructTy_ShadowFrame_fields.push_back(PointerTy_1);
StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
-StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
if (StructTy_ShadowFrame->isOpaque()) {
StructTy_ShadowFrame->setBody(StructTy_ShadowFrame_fields, /*isPacked=*/false);
}
@@ -256,6 +256,14 @@
/*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 @@
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 0e02846..6cccbe1 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 @@
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 @@
// 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 @@
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 @@
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 a6cdd9c..98129d1 100644
--- a/src/compiler_llvm/jni_compiler.h
+++ b/src/compiler_llvm/jni_compiler.h
@@ -33,10 +33,14 @@
}
namespace llvm {
+ class AllocaInst;
class Function;
class FunctionType;
+ class BasicBlock;
class LLVMContext;
class Module;
+ class Type;
+ class Value;
}
namespace art {
@@ -57,9 +61,14 @@
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 @@
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 0170148..38d7a89 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 b6ca288..ff4123a 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -425,6 +425,12 @@
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 @@
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 0b38bb7..b93138a 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -39,7 +39,6 @@
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 f413236..ac5e402 100644
--- a/src/indirect_reference_table.cc
+++ b/src/indirect_reference_table.cc
@@ -241,7 +241,7 @@
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 38266c9..7a78814 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -106,7 +106,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 f0943a7..00667ad 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2300,7 +2300,7 @@
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 c58eb29..7ba0847 100644
--- a/src/object.h
+++ b/src/object.h
@@ -774,7 +774,9 @@
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 3bdee8e..c5b6492 100644
--- a/src/shadow_frame.h
+++ b/src/shadow_frame.h
@@ -51,6 +51,16 @@
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 f3e1092..6b340d2 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1072,6 +1072,14 @@
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 @@
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 @@
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 6f91b31..6c29af2 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -265,12 +265,26 @@
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);