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