Add upcall compiler.
Upcall compiler compiles the invoke stub for native-to-managed
method invocation.
Change-Id: I09fb1e4b3f166e8da5de73e8f39509cd9be6c152
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