Implement proxy stub for compiler_llvm.

Change-Id: Id8ba59c62795d885a18b3cc634e7ef370a2d2f97
diff --git a/src/compiler_llvm/stub_compiler.cc b/src/compiler_llvm/stub_compiler.cc
new file mode 100644
index 0000000..2cf5141
--- /dev/null
+++ b/src/compiler_llvm/stub_compiler.cc
@@ -0,0 +1,270 @@
+/*
+ * 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 "stub_compiler.h"
+
+#include "compilation_unit.h"
+#include "compiled_method.h"
+#include "compiler.h"
+#include "compiler_llvm.h"
+#include "ir_builder.h"
+#include "logging.h"
+#include "object.h"
+#include "runtime_support_func.h"
+#include "utils_llvm.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;
+
+
+StubCompiler::StubCompiler(CompilationUnit* cunit, Compiler& compiler)
+: cunit_(cunit), compiler_(&compiler), module_(cunit_->GetModule()),
+  context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()) {
+}
+
+
+uint16_t StubCompiler::CreateInvokeStub(bool is_static,
+                                        char const* shorty) {
+  uint16_t elf_func_idx = cunit_->AcquireUniqueElfFuncIndex();
+
+  CHECK_NE(shorty, static_cast<char const*>(NULL));
+  size_t shorty_size = strlen(shorty);
+
+  // Function name
+  std::string func_name(ElfFuncName(elf_func_idx));
+
+  // Get argument types
+  llvm::Type* arg_types[] = {
+    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();
+
+  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_.Runtime().EmitSetCurrentThread(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, kTBAAStackTemp));
+
+    } else {
+      LOG(FATAL) << "Unexpected arg shorty for invoke stub: " << shorty[i];
+    }
+  }
+
+  // Invoke managed method now!
+  // TODO: If we solve the trampoline related problems, we can just get the code address and call.
+#if 0
+  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, kTBAAJRuntime);
+#else
+  llvm::Value* result = irb_.CreateCall(irb_.GetRuntime(FixStub), method_object_addr);
+  llvm::Value* code_addr = irb_.CreatePointerCast(result, accurate_func_type->getPointerTo());
+
+  // Exception unwind.
+  llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending();
+  llvm::BasicBlock* block_unwind = llvm::BasicBlock::Create(*context_, "exception_unwind", func);
+  llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "cont", func);
+  irb_.CreateCondBr(exception_pending, block_unwind, block_cont);
+  irb_.SetInsertPoint(block_unwind);
+  irb_.CreateRetVoid();
+  irb_.SetInsertPoint(block_cont);
+#endif
+
+  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, kTBAAStackTemp);
+  }
+
+  irb_.CreateRetVoid();
+
+  // Verify the generated function
+  VERIFY_LLVM_FUNCTION(*func);
+
+  // Add the memory usage approximation of the compilation unit
+  cunit_->AddMemUsageApproximation((shorty_size * 3 + 8) * 50);
+  // NOTE: We will emit 3 LLVM instructions per shorty for the argument,
+  // plus 3 for pointer arithmetic, and 5 for code_addr, retval, ret_addr,
+  // store ret_addr, and ret_void.  Beside, we guess that we have to use
+  // 50 bytes to represent one LLVM instruction.
+
+  return elf_func_idx;
+}
+
+uint16_t StubCompiler::CreateProxyStub(bool is_static,
+                                       char const* shorty) {
+  // Static method dosen't need proxy stub.
+  if (is_static) {
+    return NULL;
+  }
+
+  CHECK_NE(shorty, static_cast<char const*>(NULL));
+  size_t shorty_size = strlen(shorty);
+
+  uint16_t elf_func_idx = cunit_->AcquireUniqueElfFuncIndex();
+
+  // Function name
+  std::string func_name(ElfFuncName(elf_func_idx));
+
+  // 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
+  accurate_arg_types.push_back(irb_.getJObjectTy()); // this
+  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);
+
+  // Create function
+  llvm::Function* func =
+    llvm::Function::Create(accurate_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_, "proxy", func);
+  irb_.SetInsertPoint(block_body);
+
+  // JValue for proxy return
+  llvm::AllocaInst* jvalue_temp = irb_.CreateAlloca(irb_.getJValueTy());
+
+  // Load actual arguments
+  llvm::Function::arg_iterator arg_iter = func->arg_begin();
+  std::vector<llvm::Value*> args;
+  args.push_back(arg_iter++); // method
+  args.push_back(arg_iter++); // this
+  args.push_back(irb_.Runtime().EmitGetCurrentThread()); // thread
+  for (size_t i = 1; i < shorty_size; ++i) {
+    args.push_back(arg_iter++);
+  }
+  if (shorty[0] != 'V') {
+    args.push_back(jvalue_temp);
+  }
+
+  // Call ProxyInvokeHandler
+  // TODO: Partial inline ProxyInvokeHandler, don't use VarArg.
+  irb_.CreateCall(irb_.GetRuntime(ProxyInvokeHandler), args);
+  if (shorty[0] != 'V') {
+    llvm::Value* result_addr =
+        irb_.CreateBitCast(jvalue_temp, accurate_ret_type->getPointerTo());
+    llvm::Value* retval = irb_.CreateLoad(result_addr, kTBAAStackTemp);
+    irb_.CreateRet(retval);
+  } else {
+    irb_.CreateRetVoid();
+  }
+
+  // Verify the generated function
+  VERIFY_LLVM_FUNCTION(*func);
+
+  // Add the memory usage approximation of the compilation unit
+  cunit_->AddMemUsageApproximation((shorty_size + 2) * 50);
+
+  return elf_func_idx;
+}
+
+
+} // namespace compiler_llvm
+} // namespace art