1612N/A/*
2273N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
1612N/A * Copyright 2009, 2010 Red Hat, Inc.
1612N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1612N/A *
1612N/A * This code is free software; you can redistribute it and/or modify it
1612N/A * under the terms of the GNU General Public License version 2 only, as
1612N/A * published by the Free Software Foundation.
1612N/A *
1612N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1612N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1612N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1612N/A * version 2 for more details (a copy is included in the LICENSE file that
1612N/A * accompanied this code).
1612N/A *
1612N/A * You should have received a copy of the GNU General Public License version
1612N/A * 2 along with this work; if not, write to the Free Software Foundation,
1612N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1612N/A *
1612N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1612N/A * or visit www.oracle.com if you need additional information or have any
1612N/A * questions.
1612N/A *
1612N/A */
1612N/A
1879N/A#include "precompiled.hpp"
1879N/A#include "shark/llvmHeaders.hpp"
1879N/A#include "shark/sharkNativeWrapper.hpp"
1879N/A#include "shark/sharkType.hpp"
1612N/A
1612N/Ausing namespace llvm;
1612N/A
1612N/Avoid SharkNativeWrapper::initialize(const char *name) {
1612N/A // Create the function
1612N/A _function = Function::Create(
1612N/A SharkType::entry_point_type(),
1612N/A GlobalVariable::InternalLinkage,
1612N/A name);
1612N/A
1612N/A // Get our arguments
1612N/A Function::arg_iterator ai = function()->arg_begin();
1612N/A Argument *method = ai++;
1612N/A method->setName("method");
1612N/A Argument *base_pc = ai++;
1612N/A base_pc->setName("base_pc");
1612N/A code_buffer()->set_base_pc(base_pc);
1612N/A Argument *thread = ai++;
1612N/A thread->setName("thread");
1612N/A set_thread(thread);
1612N/A
1612N/A // Create and push our stack frame
1612N/A builder()->SetInsertPoint(CreateBlock());
1612N/A _stack = SharkStack::CreateBuildAndPushFrame(this, method);
1612N/A NOT_PRODUCT(method = NULL);
1612N/A
1612N/A // Create the oopmap. We use the one oopmap for every call site in
1612N/A // the wrapper, which results in the odd mild inefficiency but is a
1612N/A // damn sight easier to code.
1612N/A OopMap *oopmap = new OopMap(
1612N/A SharkStack::oopmap_slot_munge(stack()->oopmap_frame_size()),
1612N/A SharkStack::oopmap_slot_munge(arg_size()));
1612N/A oopmap->set_oop(SharkStack::slot2reg(stack()->method_slot_offset()));
1612N/A
1612N/A // Set up the oop_tmp slot if required:
1612N/A // - For static methods we use it to handlize the class argument
1612N/A // for the call, and to protect the same during slow path locks
1612N/A // (if synchronized).
1612N/A // - For methods returning oops, we use it to protect the return
1612N/A // value across safepoints or slow path unlocking.
1612N/A if (is_static() || is_returning_oop()) {
1612N/A _oop_tmp_slot = stack()->slot_addr(
1612N/A stack()->oop_tmp_slot_offset(),
1612N/A SharkType::oop_type(),
1612N/A "oop_tmp_slot");
1612N/A
1612N/A oopmap->set_oop(SharkStack::slot2reg(stack()->oop_tmp_slot_offset()));
1612N/A }
1612N/A
1612N/A // Set up the monitor slot, for synchronized methods
1612N/A if (is_synchronized()) {
1612N/A Unimplemented();
1612N/A _lock_slot_offset = 23;
1612N/A }
1612N/A
1612N/A // Start building the argument list
1612N/A std::vector<const Type*> param_types;
1612N/A std::vector<Value*> param_values;
1612N/A const PointerType *box_type = PointerType::getUnqual(SharkType::oop_type());
1612N/A
1612N/A // First argument is the JNIEnv
1612N/A param_types.push_back(SharkType::jniEnv_type());
1612N/A param_values.push_back(
1612N/A builder()->CreateAddressOfStructEntry(
1612N/A thread,
1612N/A JavaThread::jni_environment_offset(),
1612N/A SharkType::jniEnv_type(),
1612N/A "jni_environment"));
1612N/A
1612N/A // For static methods, the second argument is the class
1612N/A if (is_static()) {
1612N/A builder()->CreateStore(
1612N/A builder()->CreateInlineOop(
1612N/A JNIHandles::make_local(
2223N/A target()->method_holder()->java_mirror())),
1612N/A oop_tmp_slot());
1612N/A
1612N/A param_types.push_back(box_type);
1612N/A param_values.push_back(oop_tmp_slot());
1612N/A
1612N/A _receiver_slot_offset = stack()->oop_tmp_slot_offset();
1612N/A }
1612N/A else if (is_returning_oop()) {
1612N/A // The oop_tmp slot is registered in the oopmap,
1612N/A // so we need to clear it. This is one of the
1612N/A // mild inefficiencies I mentioned earlier.
1612N/A builder()->CreateStore(LLVMValue::null(), oop_tmp_slot());
1612N/A }
1612N/A
1612N/A // Parse the arguments
1612N/A for (int i = 0; i < arg_size(); i++) {
1612N/A int slot_offset = stack()->locals_slots_offset() + arg_size() - 1 - i;
1612N/A int adjusted_offset = slot_offset;
1612N/A BasicBlock *null, *not_null, *merge;
1612N/A Value *box;
1612N/A PHINode *phi;
1612N/A
1612N/A switch (arg_type(i)) {
1612N/A case T_VOID:
1612N/A break;
1612N/A
1612N/A case T_OBJECT:
1612N/A case T_ARRAY:
1612N/A null = CreateBlock("null");
1612N/A not_null = CreateBlock("not_null");
1612N/A merge = CreateBlock("merge");
1612N/A
1612N/A box = stack()->slot_addr(slot_offset, SharkType::oop_type());
1612N/A builder()->CreateCondBr(
1612N/A builder()->CreateICmp(
1612N/A ICmpInst::ICMP_EQ,
1612N/A builder()->CreateLoad(box),
1612N/A LLVMValue::null()),
1612N/A null, not_null);
1612N/A
1612N/A builder()->SetInsertPoint(null);
1612N/A builder()->CreateBr(merge);
1612N/A
1612N/A builder()->SetInsertPoint(not_null);
1612N/A builder()->CreateBr(merge);
1612N/A
1612N/A builder()->SetInsertPoint(merge);
1612N/A phi = builder()->CreatePHI(box_type, "boxed_object");
1612N/A phi->addIncoming(ConstantPointerNull::get(box_type), null);
1612N/A phi->addIncoming(box, not_null);
1612N/A box = phi;
1612N/A
1612N/A param_types.push_back(box_type);
1612N/A param_values.push_back(box);
1612N/A
1612N/A oopmap->set_oop(SharkStack::slot2reg(slot_offset));
1612N/A
1612N/A if (i == 0 && !is_static())
1612N/A _receiver_slot_offset = slot_offset;
1612N/A
1612N/A break;
1612N/A
1612N/A case T_LONG:
1612N/A case T_DOUBLE:
1612N/A adjusted_offset--;
1612N/A // fall through
1612N/A
1612N/A default:
1612N/A const Type *param_type = SharkType::to_stackType(arg_type(i));
1612N/A
1612N/A param_types.push_back(param_type);
1612N/A param_values.push_back(
1612N/A builder()->CreateLoad(stack()->slot_addr(adjusted_offset, param_type)));
1612N/A }
1612N/A }
1612N/A
1612N/A // The oopmap is now complete, and everything is written
1612N/A // into the frame except the PC.
1612N/A int pc_offset = code_buffer()->create_unique_offset();
1612N/A
1612N/A _oop_maps = new OopMapSet();
1612N/A oop_maps()->add_gc_map(pc_offset, oopmap);
1612N/A
1612N/A builder()->CreateStore(
1612N/A builder()->code_buffer_address(pc_offset),
1612N/A stack()->slot_addr(stack()->pc_slot_offset()));
1612N/A
1612N/A // Set up the Java frame anchor
1612N/A stack()->CreateSetLastJavaFrame();
1612N/A
1612N/A // Lock if necessary
1612N/A if (is_synchronized())
1612N/A Unimplemented();
1612N/A
1612N/A // Change the thread state to _thread_in_native
1612N/A CreateSetThreadState(_thread_in_native);
1612N/A
1612N/A // Make the call
1612N/A BasicType result_type = target()->result_type();
1612N/A const Type* return_type;
1612N/A if (result_type == T_VOID)
1612N/A return_type = SharkType::void_type();
1612N/A else if (is_returning_oop())
1612N/A return_type = box_type;
1612N/A else
1612N/A return_type = SharkType::to_arrayType(result_type);
1612N/A Value* native_function = builder()->CreateIntToPtr(
1612N/A LLVMValue::intptr_constant((intptr_t) target()->native_function()),
1612N/A PointerType::getUnqual(
1612N/A FunctionType::get(return_type, param_types, false)));
1612N/A Value *result = builder()->CreateCall(
1612N/A native_function, param_values.begin(), param_values.end());
1612N/A
1612N/A // Start the transition back to _thread_in_Java
1612N/A CreateSetThreadState(_thread_in_native_trans);
1612N/A
1612N/A // Make sure new state is visible in the GC thread
1612N/A if (os::is_MP()) {
1612N/A if (UseMembar)
1612N/A builder()->CreateMemoryBarrier(SharkBuilder::BARRIER_STORELOAD);
1612N/A else
1612N/A CreateWriteMemorySerializePage();
1612N/A }
1612N/A
1612N/A // Handle safepoint operations, pending suspend requests,
1612N/A // and pending asynchronous exceptions.
1612N/A BasicBlock *check_thread = CreateBlock("check_thread");
1612N/A BasicBlock *do_safepoint = CreateBlock("do_safepoint");
1612N/A BasicBlock *safepointed = CreateBlock("safepointed");
1612N/A
1612N/A Value *global_state = builder()->CreateLoad(
1612N/A builder()->CreateIntToPtr(
1612N/A LLVMValue::intptr_constant(
1612N/A (intptr_t) SafepointSynchronize::address_of_state()),
1612N/A PointerType::getUnqual(SharkType::jint_type())),
1612N/A "global_state");
1612N/A
1612N/A builder()->CreateCondBr(
1612N/A builder()->CreateICmpNE(
1612N/A global_state,
1612N/A LLVMValue::jint_constant(SafepointSynchronize::_not_synchronized)),
1612N/A do_safepoint, check_thread);
1612N/A
1612N/A builder()->SetInsertPoint(check_thread);
1612N/A Value *thread_state = builder()->CreateValueOfStructEntry(
1612N/A thread,
1612N/A JavaThread::suspend_flags_offset(),
1612N/A SharkType::jint_type(),
1612N/A "thread_state");
1612N/A
1612N/A builder()->CreateCondBr(
1612N/A builder()->CreateICmpNE(
1612N/A thread_state,
1612N/A LLVMValue::jint_constant(0)),
1612N/A do_safepoint, safepointed);
1612N/A
1612N/A builder()->SetInsertPoint(do_safepoint);
1612N/A builder()->CreateCall(
1612N/A builder()->check_special_condition_for_native_trans(), thread);
1612N/A builder()->CreateBr(safepointed);
1612N/A
1612N/A // Finally we can change the thread state to _thread_in_Java
1612N/A builder()->SetInsertPoint(safepointed);
1612N/A CreateSetThreadState(_thread_in_Java);
1612N/A
1612N/A // Clear the frame anchor
1612N/A stack()->CreateResetLastJavaFrame();
1612N/A
1612N/A // If there is a pending exception then we can just unwind and
1612N/A // return. It seems totally wrong that unlocking is skipped here
1612N/A // but apparently the template interpreter does this so we do too.
1612N/A BasicBlock *exception = CreateBlock("exception");
1612N/A BasicBlock *no_exception = CreateBlock("no_exception");
1612N/A
1612N/A builder()->CreateCondBr(
1612N/A builder()->CreateICmpEQ(
1612N/A CreateLoadPendingException(),
1612N/A LLVMValue::null()),
1612N/A no_exception, exception);
1612N/A
1612N/A builder()->SetInsertPoint(exception);
1612N/A CreateResetHandleBlock();
1612N/A stack()->CreatePopFrame(0);
1612N/A builder()->CreateRet(LLVMValue::jint_constant(0));
1612N/A
1612N/A builder()->SetInsertPoint(no_exception);
1612N/A
1612N/A // If the result was an oop then unbox it before
1612N/A // releasing the handle it might be protected by
1612N/A if (is_returning_oop()) {
1612N/A BasicBlock *null = builder()->GetInsertBlock();
1612N/A BasicBlock *not_null = CreateBlock("not_null");
1612N/A BasicBlock *merge = CreateBlock("merge");
1612N/A
1612N/A builder()->CreateCondBr(
1612N/A builder()->CreateICmpNE(result, ConstantPointerNull::get(box_type)),
1612N/A not_null, merge);
1612N/A
1612N/A builder()->SetInsertPoint(not_null);
1612N/A Value *unboxed_result = builder()->CreateLoad(result);
1612N/A builder()->CreateBr(merge);
1612N/A
1612N/A builder()->SetInsertPoint(merge);
1612N/A PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), "result");
1612N/A phi->addIncoming(LLVMValue::null(), null);
1612N/A phi->addIncoming(unboxed_result, not_null);
1612N/A result = phi;
1612N/A }
1612N/A
1612N/A // Reset handle block
1612N/A CreateResetHandleBlock();
1612N/A
1612N/A // Unlock if necessary.
1612N/A if (is_synchronized())
1612N/A Unimplemented();
1612N/A
1612N/A // Unwind and return
1612N/A Value *result_addr = stack()->CreatePopFrame(type2size[result_type]);
1612N/A if (result_type != T_VOID) {
1612N/A bool needs_cast = false;
1612N/A bool is_signed = false;
1612N/A switch (result_type) {
1612N/A case T_BOOLEAN:
1612N/A result = builder()->CreateICmpNE(result, LLVMValue::jbyte_constant(0));
1612N/A needs_cast = true;
1612N/A break;
1612N/A
1612N/A case T_CHAR:
1612N/A needs_cast = true;
1612N/A break;
1612N/A
1612N/A case T_BYTE:
1612N/A case T_SHORT:
1612N/A needs_cast = true;
1612N/A is_signed = true;
1612N/A break;
1612N/A }
1612N/A if (needs_cast) {
1612N/A result = builder()->CreateIntCast(
1612N/A result, SharkType::to_stackType(result_type), is_signed);
1612N/A }
1612N/A
1612N/A builder()->CreateStore(
1612N/A result,
1612N/A builder()->CreateIntToPtr(
1612N/A result_addr,
1612N/A PointerType::getUnqual(SharkType::to_stackType(result_type))));
1612N/A }
1612N/A builder()->CreateRet(LLVMValue::jint_constant(0));
1612N/A}