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);