Add upcall compiler.

Upcall compiler compiles the invoke stub for native-to-managed
method invocation.

Change-Id: I09fb1e4b3f166e8da5de73e8f39509cd9be6c152
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 8c16295..4bf0319 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -180,8 +180,6 @@
 	src/jdwp/jdwp_socket.cc \
 	src/jni_compiler.cc \
 	src/jni_internal.cc \
-	src/jni_internal_arm.cc \
-	src/jni_internal_x86.cc \
 	src/logging.cc \
 	src/mark_stack.cc \
 	src/mark_sweep.cc \
@@ -227,6 +225,7 @@
 	src/compiler_llvm/ir_builder.cc \
 	src/compiler_llvm/inferred_reg_category_map.cc \
 	src/compiler_llvm/method_compiler.cc \
+	src/compiler_llvm/upcall_compiler.cc \
 	src/compiler_llvm/utils_llvm.cc
 else
 LIBART_COMMON_SRC_FILES += \
@@ -241,7 +240,9 @@
 	src/compiler/codegen/arm/ArmRallocUtil.cc \
 	src/compiler/codegen/arm/Assemble.cc \
 	src/compiler/codegen/arm/LocalOptimizations.cc \
-	src/compiler/codegen/arm/armv7-a/Codegen.cc
+	src/compiler/codegen/arm/armv7-a/Codegen.cc \
+	src/jni_internal_arm.cc \
+	src/jni_internal_x86.cc
 endif
 
 LIBART_TARGET_SRC_FILES := \
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
index 7c7460c..3c3f6ef 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -171,10 +171,16 @@
   }
 }
 
+#if defined(ART_USE_LLVM_COMPILER)
+CompiledInvokeStub::CompiledInvokeStub(llvm::Function* func) : func_(func) {
+  CHECK_NE(func, static_cast<llvm::Function*>(NULL));
+}
+#else
 CompiledInvokeStub::CompiledInvokeStub(std::vector<uint8_t>& code) {
   CHECK_NE(code.size(), 0U);
   code_ = code;
 }
+#endif
 
 CompiledInvokeStub::~CompiledInvokeStub() {}
 
diff --git a/src/compiled_method.h b/src/compiled_method.h
index 834ead0..d11f0e4 100644
--- a/src/compiled_method.h
+++ b/src/compiled_method.h
@@ -98,10 +98,17 @@
 
 class CompiledInvokeStub {
  public:
+#if defined(ART_USE_LLVM_COMPILER)
+  explicit CompiledInvokeStub(llvm::Function* func);
+#else
   explicit CompiledInvokeStub(std::vector<uint8_t>& code);
+#endif
   ~CompiledInvokeStub();
   const std::vector<uint8_t>& GetCode() const;
  private:
+#if defined(ART_USE_LLVM_COMPILER)
+  llvm::Function* func_;
+#endif
   std::vector<uint8_t> code_;
 };
 
diff --git a/src/compiler.cc b/src/compiler.cc
index 08c6cc4..c917736 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -988,6 +988,9 @@
   bool is_static = (access_flags & kAccStatic) != 0;
   const CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(is_static, shorty);
   if (compiled_invoke_stub == NULL) {
+#if defined(ART_USE_LLVM_COMPILER)
+    compiled_invoke_stub = compiler_llvm_->CreateInvokeStub(is_static, shorty);
+#else
     if (instruction_set_ == kX86) {
       compiled_invoke_stub = ::art::x86::X86CreateInvokeStub(is_static, shorty);
     } else {
@@ -995,6 +998,8 @@
       // Generates invocation stub using ARM instruction set
       compiled_invoke_stub = ::art::arm::ArmCreateInvokeStub(is_static, shorty);
     }
+#endif
+
     CHECK(compiled_invoke_stub != NULL);
     InsertInvokeStub(is_static, shorty, compiled_invoke_stub);
   }
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 8a9b362..21a7bb9 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -19,6 +19,7 @@
 #include "compiler.h"
 #include "ir_builder.h"
 #include "method_compiler.h"
+#include "upcall_compiler.h"
 
 #include <llvm/ADT/OwningPtr.h>
 #include <llvm/Bitcode/ReaderWriter.h>
@@ -104,5 +105,17 @@
 }
 
 
+CompiledInvokeStub* CompilerLLVM::CreateInvokeStub(bool is_static,
+                                                   char const *shorty) {
+
+  MutexLock GUARD(compiler_lock_);
+
+  UniquePtr<UpcallCompiler> upcall_compiler(
+    new UpcallCompiler(insn_set_, *compiler_));
+
+  return upcall_compiler->CreateStub(is_static, shorty);
+}
+
+
 } // namespace compiler_llvm
 } // namespace art
diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h
index 0de28f5..f39f686 100644
--- a/src/compiler_llvm/compiler_llvm.h
+++ b/src/compiler_llvm/compiler_llvm.h
@@ -27,6 +27,7 @@
 
 namespace art {
   class ClassLoader;
+  class CompiledInvokeStub;
   class CompiledMethod;
   class Compiler;
 }
@@ -83,6 +84,8 @@
                                    ClassLoader const* class_loader,
                                    DexFile const& dex_file);
 
+  CompiledInvokeStub* CreateInvokeStub(bool is_static, char const *shorty);
+
  private:
   Compiler* compiler_;
 
diff --git a/src/compiler_llvm/ir_builder.cc b/src/compiler_llvm/ir_builder.cc
index b2c795b..4c43271 100644
--- a/src/compiler_llvm/ir_builder.cc
+++ b/src/compiler_llvm/ir_builder.cc
@@ -35,6 +35,10 @@
   CHECK_NE(jobject_struct_type, static_cast<llvm::Type*>(NULL));
   jobject_type_ = jobject_struct_type->getPointerTo();
 
+  // Create JEnv* type
+  llvm::Type* jenv_struct_type = llvm::StructType::create(context, "JEnv");
+  jenv_type_ = jenv_struct_type->getPointerTo();
+
   // Load the runtime support function declaration from module
   InitRuntimeSupportFuncDecl(module);
 }
diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h
index 617ed8d..b38c7b0 100644
--- a/src/compiler_llvm/ir_builder.h
+++ b/src/compiler_llvm/ir_builder.h
@@ -162,6 +162,18 @@
     return jobject_type_;
   }
 
+  llvm::PointerType* getJEnvTy() {
+    return jenv_type_;
+  }
+
+  llvm::Type* getJValueTy() {
+    // NOTE: JValue is an union type, which may contains boolean, byte, char,
+    // short, int, long, float, double, Object.  However, LLVM itself does
+    // not support union type, so we have to return a type with biggest size,
+    // then bitcast it before we use it.
+    return getJLongTy();
+  }
+
 
   //--------------------------------------------------------------------------
   // Constant Value Helper Function
@@ -266,6 +278,8 @@
  private:
   llvm::PointerType* jobject_type_;
 
+  llvm::PointerType* jenv_type_;
+
   llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID];
 
 };
diff --git a/src/compiler_llvm/upcall_compiler.cc b/src/compiler_llvm/upcall_compiler.cc
new file mode 100644
index 0000000..308790a
--- /dev/null
+++ b/src/compiler_llvm/upcall_compiler.cc
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "upcall_compiler.h"
+
+#include "compiler.h"
+#include "compiled_method.h"
+#include "compiler_llvm.h"
+#include "ir_builder.h"
+#include "logging.h"
+#include "object.h"
+#include "runtime_support_func.h"
+
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/BasicBlock.h>
+#include <llvm/Function.h>
+#include <llvm/GlobalVariable.h>
+#include <llvm/Intrinsics.h>
+
+#include <string>
+#include <string.h>
+
+namespace art {
+namespace compiler_llvm {
+
+using namespace runtime_support;
+
+
+UpcallCompiler::UpcallCompiler(InstructionSet insn_set,
+                               Compiler& compiler)
+: insn_set_(insn_set), compiler_(&compiler),
+  compiler_llvm_(compiler_->GetCompilerLLVM()),
+  module_(compiler_llvm_->GetModule()),
+  context_(compiler_llvm_->GetLLVMContext()),
+  irb_(*compiler_llvm_->GetIRBuilder()) {
+}
+
+
+CompiledInvokeStub* UpcallCompiler::CreateStub(bool is_static,
+                                               char const* shorty) {
+
+  CHECK_NE(shorty, static_cast<char const*>(NULL));
+  size_t shorty_size = strlen(shorty);
+
+  // Function name
+  std::string func_name;
+
+  if (is_static) {
+    StringAppendF(&func_name, "ArtSUpcall_%s", shorty);
+  } else {
+    StringAppendF(&func_name, "ArtUpcall_%s", shorty);
+  }
+
+  // Get argument types
+  llvm::Type* arg_types[] = {
+    irb_.getJEnvTy(), // JEnv*
+    irb_.getJObjectTy(), // Method object pointer
+    irb_.getJObjectTy(), // "this" object pointer (NULL for static)
+    irb_.getJObjectTy(), // Thread object pointer
+    irb_.getJValueTy()->getPointerTo(),
+    irb_.getJValueTy()->getPointerTo(),
+  };
+
+  // Function type
+  llvm::FunctionType* func_type =
+    llvm::FunctionType::get(irb_.getVoidTy(), arg_types, false);
+
+  // Create function
+  llvm::Function* func =
+    llvm::Function::Create(func_type, llvm::Function::ExternalLinkage,
+                           func_name, module_);
+
+
+  // Create basic block for the body of this function
+  llvm::BasicBlock* block_body =
+    llvm::BasicBlock::Create(*context_, "upcall", func);
+
+  irb_.SetInsertPoint(block_body);
+
+  // Actual arguments
+  llvm::Function::arg_iterator arg_iter = func->arg_begin();
+
+  arg_iter++; // jenv_addr
+  llvm::Value* method_object_addr = arg_iter++;
+  llvm::Value* callee_this_addr = arg_iter++;
+  llvm::Value* thread_object_addr = arg_iter++;
+  llvm::Value* actual_args_array_addr = arg_iter++;
+  llvm::Value* retval_addr = arg_iter++;
+
+  // Setup thread pointer
+  irb_.CreateCall(irb_.GetRuntime(SetCurrentThread), thread_object_addr);
+
+  // Accurate function type
+  llvm::Type* accurate_ret_type = irb_.getJType(shorty[0], kAccurate);
+
+  std::vector<llvm::Type*> accurate_arg_types;
+
+  accurate_arg_types.push_back(irb_.getJObjectTy()); // method object pointer
+
+  if (!is_static) {
+    accurate_arg_types.push_back(irb_.getJObjectTy());
+  }
+
+  for (size_t i = 1; i < shorty_size; ++i) {
+    accurate_arg_types.push_back(irb_.getJType(shorty[i], kAccurate));
+  }
+
+  llvm::FunctionType* accurate_func_type =
+    llvm::FunctionType::get(accurate_ret_type, accurate_arg_types, false);
+
+  // Load actual arguments
+  std::vector<llvm::Value*> args;
+
+  args.push_back(method_object_addr);
+
+  if (!is_static) {
+    args.push_back(callee_this_addr);
+  }
+
+  for (size_t i = 1; i < shorty_size; ++i) {
+    char arg_shorty = shorty[i];
+
+    if (arg_shorty == 'Z' || arg_shorty == 'B' || arg_shorty == 'C' ||
+        arg_shorty == 'S' || arg_shorty == 'I' || arg_shorty == 'J' ||
+        arg_shorty == 'F' || arg_shorty == 'D' || arg_shorty == 'L') {
+
+      llvm::Type* arg_type =
+        irb_.getJType(shorty[i], kAccurate)->getPointerTo();
+
+      llvm::Value* arg_jvalue_addr =
+        irb_.CreateConstGEP1_32(actual_args_array_addr, i - 1);
+
+      llvm::Value* arg_addr = irb_.CreateBitCast(arg_jvalue_addr, arg_type);
+
+      args.push_back(irb_.CreateLoad(arg_addr));
+
+    } else {
+      LOG(ERROR) << "Unexpected arg shorty for invoke stub: " << shorty[i];
+    }
+  }
+
+  // Invoke managed method now!
+  llvm::Value* code_field_offset_value =
+    irb_.getPtrEquivInt(Method::GetCodeOffset().Int32Value());
+
+  llvm::Value* code_field_addr =
+    irb_.CreatePtrDisp(method_object_addr, code_field_offset_value,
+                       accurate_func_type->getPointerTo()->getPointerTo());
+
+  llvm::Value* code_addr = irb_.CreateLoad(code_field_addr);
+
+  llvm::Value* retval = irb_.CreateCall(code_addr, args);
+
+  // Store the returned value
+  if (shorty[0] != 'V') {
+    llvm::Value* ret_addr =
+      irb_.CreateBitCast(retval_addr, accurate_ret_type->getPointerTo());
+
+    irb_.CreateStore(retval, ret_addr);
+  }
+
+  irb_.CreateRetVoid();
+
+  llvm::verifyFunction(*func, llvm::PrintMessageAction);
+
+  return new CompiledInvokeStub(func);
+}
+
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/upcall_compiler.h b/src/compiler_llvm/upcall_compiler.h
new file mode 100644
index 0000000..426919e
--- /dev/null
+++ b/src/compiler_llvm/upcall_compiler.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_LLVM_UPCALL_COMPILER_H_
+#define ART_SRC_COMPILER_LLVM_UPCALL_COMPILER_H_
+
+#include "constants.h"
+
+#include <stdint.h>
+
+namespace art {
+  class CompiledInvokeStub;
+  class Compiler;
+}
+
+namespace llvm {
+  class LLVMContext;
+  class Module;
+}
+
+namespace art {
+namespace compiler_llvm {
+
+class CompilerLLVM;
+class IRBuilder;
+
+class UpcallCompiler {
+ public:
+  UpcallCompiler(InstructionSet insn_set, Compiler& compiler);
+
+  CompiledInvokeStub* CreateStub(bool is_static, char const* shorty);
+
+ private:
+  InstructionSet insn_set_;
+  Compiler const* compiler_;
+  CompilerLLVM* compiler_llvm_;
+  llvm::Module* module_;
+  llvm::LLVMContext* context_;
+  IRBuilder& irb_;
+};
+
+
+} // namespace compiler_llvm
+} // namespace art
+
+
+#endif // ART_SRC_COMPILER_LLVM_UPCALL_COMPILER_H_