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/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
 //----------------------------------------------------------------------------