# HG changeset patch # User Gary Benson # Date 1236181273 18000 # Node ID b593d3ef9dce396c5355ea00592750acbd9337a7 # Parent 22425c2ed9a9cdbf34bcb5517431674cea31d05c 2009-03-04 Gary Benson * ports/hotspot/src/share/vm/shark/sharkInliner.hpp: New file. * ports/hotspot/src/share/vm/shark/sharkInliner.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkBlock.hpp: Moved partly into... * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp: New file. * ports/hotspot/src/share/vm/shark/sharkBlock.cpp: Likewise into... * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp: New file. * ports/hotspot/src/share/vm/shark/sharkState.hpp: Merged SharkTrackingState into SharkState, and moved SharkEntryState into sharkFunction.cpp and SharkPHIState into sharkTopLevelBlock.cpp. * ports/hotspot/src/share/vm/shark/sharkState.inline.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkState.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp: s/SharkBlock/SharkTopLevelBlock/g * ports/hotspot/src/share/vm/shark/sharkMonitor.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkMonitor.cpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkFunction.hpp: Likewise. * ports/hotspot/src/share/vm/shark/sharkFunction.cpp: Likewise. * ports/hotspot/src/share/vm/shark/shark_globals.hpp (SharkMaxInlineSize): New parameter. * ports/hotspot/src/share/vm/shark/sharkBuilder.hpp (SharkBuilder::GetBlockInsertionPoint): New method. (SharkBuilder::CreateBlock): Likewise. * ports/hotspot/src/share/vm/includeDB_shark: Updated. diff -r 22425c2ed9a9 -r b593d3ef9dce ChangeLog --- a/ChangeLog Wed Mar 04 11:01:54 2009 +0100 +++ b/ChangeLog Wed Mar 04 10:41:13 2009 -0500 @@ -1,3 +1,36 @@ +2009-03-04 Gary Benson + + * ports/hotspot/src/share/vm/shark/sharkInliner.hpp: New file. + * ports/hotspot/src/share/vm/shark/sharkInliner.cpp: Likewise. + + * ports/hotspot/src/share/vm/shark/sharkBlock.hpp: Moved partly into... + * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp: New file. + * ports/hotspot/src/share/vm/shark/sharkBlock.cpp: Likewise into... + * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp: New file. + + * ports/hotspot/src/share/vm/shark/sharkState.hpp: + Merged SharkTrackingState into SharkState, and moved + SharkEntryState into sharkFunction.cpp and SharkPHIState + into sharkTopLevelBlock.cpp. + * ports/hotspot/src/share/vm/shark/sharkState.inline.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkState.cpp: Likewise. + + * ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp: + s/SharkBlock/SharkTopLevelBlock/g + * ports/hotspot/src/share/vm/shark/sharkMonitor.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkMonitor.cpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkFunction.hpp: Likewise. + * ports/hotspot/src/share/vm/shark/sharkFunction.cpp: Likewise. + + * ports/hotspot/src/share/vm/shark/shark_globals.hpp + (SharkMaxInlineSize): New parameter. + + * ports/hotspot/src/share/vm/shark/sharkBuilder.hpp + (SharkBuilder::GetBlockInsertionPoint): New method. + (SharkBuilder::CreateBlock): Likewise. + + * ports/hotspot/src/share/vm/includeDB_shark: Updated. + 2009-03-04 Matthias Klose * configure.ac: Set version to 1.5pre. diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/includeDB_shark --- a/ports/hotspot/src/share/vm/includeDB_shark Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/includeDB_shark Wed Mar 04 10:41:13 2009 -0500 @@ -25,6 +25,25 @@ // NOTE: DO NOT CHANGE THIS COPYRIGHT TO NEW STYLE - IT WILL BREAK makeDeps! +sharkBlock.cpp debug.hpp +sharkBlock.cpp bytecodes.hpp +sharkBlock.cpp llvmHeaders.hpp +sharkBlock.cpp shark_globals.hpp +sharkBlock.cpp sharkBlock.hpp +sharkBlock.cpp sharkBuilder.hpp +sharkBlock.cpp sharkRuntime.hpp +sharkBlock.cpp sharkState.inline.hpp +sharkBlock.cpp sharkValue.inline.hpp + +sharkBlock.hpp allocation.hpp +sharkBlock.hpp ciMethod.hpp +sharkBlock.hpp ciStreams.hpp +sharkBlock.hpp debug.hpp +sharkBlock.hpp llvmHeaders.hpp +sharkBlock.hpp sharkBuilder.hpp +sharkBlock.hpp sharkState.hpp +sharkBlock.hpp sharkValue.hpp + ciMethod.cpp ciTypeFlow.hpp ciMethod.cpp methodOop.hpp @@ -63,33 +82,35 @@ shark_globals.hpp shark_globals_.hpp shark_globals.hpp globals.hpp -sharkBlock.cpp allocation.hpp -sharkBlock.cpp bytecodes.hpp -sharkBlock.cpp ciField.hpp -sharkBlock.cpp ciStreams.hpp -sharkBlock.cpp ciType.hpp -sharkBlock.cpp ciTypeFlow.hpp -sharkBlock.cpp debug.hpp -sharkBlock.cpp llvmHeaders.hpp -sharkBlock.cpp shark_globals.hpp -sharkBlock.cpp sharkBlock.hpp -sharkBlock.cpp sharkBuilder.hpp -sharkBlock.cpp sharkConstantPool.hpp -sharkBlock.cpp sharkRuntime.hpp -sharkBlock.cpp sharkState.inline.hpp -sharkBlock.cpp sharkValue.inline.hpp +sharkTopLevelBlock.cpp allocation.hpp +sharkTopLevelBlock.cpp bytecodes.hpp +sharkTopLevelBlock.cpp ciField.hpp +sharkTopLevelBlock.cpp ciStreams.hpp +sharkTopLevelBlock.cpp ciType.hpp +sharkTopLevelBlock.cpp ciTypeFlow.hpp +sharkTopLevelBlock.cpp debug.hpp +sharkTopLevelBlock.cpp llvmHeaders.hpp +sharkTopLevelBlock.cpp shark_globals.hpp +sharkTopLevelBlock.cpp sharkTopLevelBlock.hpp +sharkTopLevelBlock.cpp sharkBuilder.hpp +sharkTopLevelBlock.cpp sharkConstantPool.hpp +sharkTopLevelBlock.cpp sharkInliner.hpp +sharkTopLevelBlock.cpp sharkRuntime.hpp +sharkTopLevelBlock.cpp sharkState.inline.hpp +sharkTopLevelBlock.cpp sharkValue.inline.hpp -sharkBlock.hpp allocation.hpp -sharkBlock.hpp bytecodes.hpp -sharkBlock.hpp ciStreams.hpp -sharkBlock.hpp ciType.hpp -sharkBlock.hpp ciTypeFlow.hpp -sharkBlock.hpp llvmHeaders.hpp -sharkBlock.hpp sharkBuilder.hpp -sharkBlock.hpp sharkFunction.hpp -sharkBlock.hpp sharkMonitor.hpp -sharkBlock.hpp sharkState.hpp -sharkBlock.hpp sharkValue.inline.hpp +sharkTopLevelBlock.hpp allocation.hpp +sharkTopLevelBlock.hpp bytecodes.hpp +sharkTopLevelBlock.hpp ciStreams.hpp +sharkTopLevelBlock.hpp ciType.hpp +sharkTopLevelBlock.hpp ciTypeFlow.hpp +sharkTopLevelBlock.hpp llvmHeaders.hpp +sharkTopLevelBlock.hpp sharkBlock.hpp +sharkTopLevelBlock.hpp sharkBuilder.hpp +sharkTopLevelBlock.hpp sharkFunction.hpp +sharkTopLevelBlock.hpp sharkMonitor.hpp +sharkTopLevelBlock.hpp sharkState.inline.hpp +sharkTopLevelBlock.hpp sharkValue.inline.hpp sharkBuilder.cpp ciMethod.hpp sharkBuilder.cpp debug.hpp @@ -163,8 +184,8 @@ sharkConstantPool.hpp allocation.hpp sharkConstantPool.hpp llvmHeaders.hpp -sharkConstantPool.hpp sharkBlock.hpp sharkConstantPool.hpp sharkBuilder.hpp +sharkConstantPool.hpp sharkTopLevelBlock.hpp sharkEntry.cpp sharkEntry.hpp @@ -175,12 +196,12 @@ sharkFunction.cpp debug.hpp sharkFunction.cpp llvmHeaders.hpp sharkFunction.cpp shark_globals.hpp -sharkFunction.cpp sharkBlock.hpp sharkFunction.cpp sharkBuilder.hpp sharkFunction.cpp sharkEntry.hpp sharkFunction.cpp sharkFunction.hpp sharkFunction.cpp sharkMonitor.hpp sharkFunction.cpp sharkState.inline.hpp +sharkFunction.cpp sharkTopLevelBlock.hpp sharkFunction.hpp allocation.hpp sharkFunction.hpp ciEnv.hpp @@ -189,11 +210,25 @@ sharkFunction.hpp llvmHeaders.hpp sharkFunction.hpp sharkBuilder.hpp +sharkInliner.cpp allocation.hpp +sharkInliner.cpp bytecodes.hpp +sharkInliner.cpp ciField.hpp +sharkInliner.cpp ciMethod.hpp +sharkInliner.cpp ciStreams.hpp +sharkInliner.cpp shark_globals.hpp +sharkInliner.cpp sharkInliner.hpp +sharkInliner.cpp sharkState.inline.hpp +sharkInliner.cpp sharkValue.inline.hpp + +sharkInliner.hpp allocation.hpp +sharkInliner.hpp ciMethod.hpp +sharkInliner.hpp sharkState.inline.hpp + sharkMonitor.cpp llvmHeaders.hpp -sharkMonitor.cpp sharkBlock.hpp sharkMonitor.cpp sharkMonitor.hpp sharkMonitor.cpp sharkRuntime.hpp sharkMonitor.cpp sharkState.inline.hpp +sharkMonitor.cpp sharkTopLevelBlock.hpp sharkMonitor.hpp allocation.hpp sharkMonitor.hpp llvmHeaders.hpp @@ -218,21 +253,22 @@ sharkState.cpp allocation.hpp sharkState.cpp ciType.hpp sharkState.cpp ciTypeFlow.hpp -sharkState.cpp sharkBlock.hpp sharkState.cpp sharkBuilder.hpp +sharkState.cpp sharkCacheDecache.hpp sharkState.cpp sharkState.inline.hpp +sharkState.cpp sharkTopLevelBlock.hpp sharkState.cpp sharkType.hpp sharkState.cpp sharkValue.inline.hpp sharkState.hpp allocation.hpp +sharkState.hpp ciMethod.hpp +sharkState.hpp llvmHeaders.hpp sharkState.hpp sharkBuilder.hpp -sharkState.hpp sharkFunction.hpp -sharkState.hpp sharkValue.inline.hpp -sharkState.hpp vmreg.hpp +sharkState.hpp sharkValue.hpp sharkState.inline.hpp sharkBlock.hpp +sharkState.inline.hpp sharkBuilder.hpp sharkState.inline.hpp sharkState.hpp -sharkState.inline.hpp sharkCacheDecache.hpp sharkStateScanner.cpp sharkState.inline.hpp sharkStateScanner.cpp sharkStateScanner.hpp diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkBlock.cpp --- a/ports/hotspot/src/share/vm/shark/sharkBlock.cpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkBlock.cpp Wed Mar 04 10:41:13 2009 -0500 @@ -25,112 +25,26 @@ #include "incls/_precompiled.incl" #include "incls/_sharkBlock.cpp.incl" -#include "ciArrayKlass.hpp" // XXX fuck you makeDeps -#include "ciObjArrayKlass.hpp" // XXX likewise using namespace llvm; -void SharkBlock::enter(SharkBlock* predecessor, bool is_exception) -{ - // This block requires phis: - // - if it is entered more than once - // - if it is an exception handler, because in which - // case we assume it's entered more than once. - // - if the predecessor will be compiled after this - // block, in which case we can't simple propagate - // the state forward. - if (!needs_phis() && - (entered() || - is_exception || - (predecessor && predecessor->index() >= index()))) - _needs_phis = true; - - // Recurse into the tree - if (!entered()) { - _entered = true; - - if (!has_trap()) { - for (int i = 0; i < num_successors(); i++) { - successor(i)->enter(this, false); - } - for (int i = 0; i < num_exceptions(); i++) { - exception(i)->enter(this, true); - } - } - } -} - -void SharkBlock::initialize() -{ - char name[28]; - snprintf(name, sizeof(name), - "bci_%d%s", - start(), is_private_copy() ? "_private_copy" : ""); - _entry_block = function()->CreateBlock(name); -} - -void SharkBlock::acquire_method_lock() -{ - Value *object; - if (target()->is_static()) { - SharkConstantPool constants(this); - object = constants.java_mirror(); - } - else { - object = local(0)->jobject_value(); - } - iter()->force_bci(start()); // for the decache - function()->monitor(0)->acquire(this, object); - check_pending_exception(false); -} - -void SharkBlock::release_method_lock() -{ - function()->monitor(0)->release(this); - - // We neither need nor want to check for pending exceptions here. - // This method is only called by handle_return, which copes with - // them implicitly: - // - if a value is being returned then we just carry on as normal; - // the caller will see the pending exception and handle it. - // - if an exception is being thrown then that exception takes - // priority and ours will be ignored. -} - -void SharkBlock::parse() +void SharkBlock::parse_bytecode(int start, int limit) { SharkValue *a, *b, *c, *d; int i; - builder()->SetInsertPoint(entry_block()); - - if (has_trap()) { - iter()->force_bci(start()); - - current_state()->decache_for_trap(); - builder()->CreateCall2( - SharkRuntime::uncommon_trap(), - thread(), - LLVMValue::jint_constant(trap_index())); - builder()->CreateRetVoid(); - return; - } - - iter()->reset_to_bci(start()); - bool successors_done = false; - while (iter()->next() != ciBytecodeStream::EOBC() && bci() < limit()) { - NOT_PRODUCT(a = b = c = d = NULL); + iter()->reset_to_bci(start); + while (iter()->next_bci() < limit) { + NOT_PRODUCT(a = b = c = d = NULL); + iter()->next(); if (SharkTraceBytecodes) tty->print_cr("%4d: %s", bci(), Bytecodes::name(bc())); - if(UseLoopSafepoints) { - int len; - + if (UseLoopSafepoints) { // XXX if a lcmp is followed by an if_?? then C2 maybe-inserts // the safepoint before the lcmp rather than before the if. // Maybe we should do this too. See parse2.cpp for details. - switch (bc()) { case Bytecodes::_goto: case Bytecodes::_ifnull: @@ -164,15 +78,15 @@ add_safepoint(); break; } - len = switch_table_length(); - for (i = 0; i < len; i++) { + int len = switch_table_length(); + for (int i = 0; i < len; i++) { if (switch_dest(i) <= bci()) { add_safepoint(); break; } } break; - } + } } switch (bc()) { @@ -809,19 +723,16 @@ case Bytecodes::_goto: case Bytecodes::_goto_w: - builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); + do_goto(); break; case Bytecodes::_jsr: case Bytecodes::_jsr_w: - push(SharkValue::create_returnAddress(iter()->next_bci())); - builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); + do_jsr(); break; case Bytecodes::_ret: - assert(local(iter()->get_index())->returnAddress_value() == - successor(ciTypeFlow::GOTO_TARGET)->start(), "should be"); - builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); + do_ret(); break; case Bytecodes::_ifnull: @@ -831,11 +742,13 @@ do_if(ICmpInst::ICMP_NE, SharkValue::null(), pop()); break; case Bytecodes::_if_acmpeq: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_EQ, b, a); break; case Bytecodes::_if_acmpne: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_NE, b, a); break; case Bytecodes::_ifeq: @@ -857,34 +770,39 @@ do_if(ICmpInst::ICMP_SGE, SharkValue::jint_constant(0), pop()); break; case Bytecodes::_if_icmpeq: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_EQ, b, a); break; case Bytecodes::_if_icmpne: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_NE, b, a); break; case Bytecodes::_if_icmplt: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_SLT, b, a); break; case Bytecodes::_if_icmple: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_SLE, b, a); break; case Bytecodes::_if_icmpgt: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_SGT, b, a); break; case Bytecodes::_if_icmpge: - b = pop(); a = pop(); + b = pop(); + a = pop(); do_if(ICmpInst::ICMP_SGE, b, a); break; case Bytecodes::_tableswitch: case Bytecodes::_lookupswitch: do_switch(); - successors_done = true; break; case Bytecodes::_invokestatic: @@ -923,775 +841,11 @@ ShouldNotReachHere(); } } - - if (falls_through()) { - builder()->CreateBr(successor(ciTypeFlow::FALL_THROUGH)->entry_block()); - } - - if (!successors_done) { - for (int i = 0; i < num_successors(); i++) - successor(i)->add_incoming(current_state()); - } -} - -SharkBlock* SharkBlock::bci_successor(int bci) const -{ - // XXX now with Linear Search Technology (tm) - for (int i = 0; i < num_successors(); i++) { - ciTypeFlow::Block *successor = ciblock()->successors()->at(i); - if (successor->start() == bci) - return function()->block(successor->pre_order()); - } - ShouldNotReachHere(); -} - -void SharkBlock::check_zero(SharkValue *value) -{ - if (value->zero_checked()) - return; - - BasicBlock *zero = function()->CreateBlock("zero"); - BasicBlock *not_zero = function()->CreateBlock("not_zero"); - - Value *a, *b; - switch (value->basic_type()) { - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - a = value->jint_value(); - b = LLVMValue::jint_constant(0); - break; - case T_LONG: - a = value->jlong_value(); - b = LLVMValue::jlong_constant(0); - break; - case T_OBJECT: - case T_ARRAY: - a = value->jobject_value(); - b = LLVMValue::LLVMValue::null(); - break; - default: - tty->print_cr("Unhandled type %s", type2name(value->basic_type())); - ShouldNotReachHere(); - } - - builder()->CreateCondBr(builder()->CreateICmpNE(a, b), not_zero, zero); - - builder()->SetInsertPoint(zero); - SharkTrackingState *saved_state = current_state()->copy(); - if (value->is_jobject()) { - call_vm_nocheck( - SharkRuntime::throw_NullPointerException(), - builder()->pointer_constant(__FILE__), - LLVMValue::jint_constant(__LINE__)); - } - else { - builder()->CreateUnimplemented(__FILE__, __LINE__); - } - handle_exception(function()->CreateGetPendingException()); - set_current_state(saved_state); - - builder()->SetInsertPoint(not_zero); - - value->set_zero_checked(true); -} - -void SharkBlock::check_bounds(SharkValue* array, SharkValue* index) -{ - BasicBlock *out_of_bounds = function()->CreateBlock("out_of_bounds"); - BasicBlock *in_bounds = function()->CreateBlock("in_bounds"); - - Value *length = builder()->CreateArrayLength(array->jarray_value()); - // we use an unsigned comparison to catch negative values - builder()->CreateCondBr( - builder()->CreateICmpULT(index->jint_value(), length), - in_bounds, out_of_bounds); - - builder()->SetInsertPoint(out_of_bounds); - SharkTrackingState *saved_state = current_state()->copy(); - call_vm_nocheck( - SharkRuntime::throw_ArrayIndexOutOfBoundsException(), - builder()->pointer_constant(__FILE__), - LLVMValue::jint_constant(__LINE__), - index->jint_value()); - handle_exception(function()->CreateGetPendingException()); - set_current_state(saved_state); - - builder()->SetInsertPoint(in_bounds); -} - -void SharkBlock::check_pending_exception(bool attempt_catch) -{ - BasicBlock *exception = function()->CreateBlock("exception"); - BasicBlock *no_exception = function()->CreateBlock("no_exception"); - - Value *pending_exception_addr = function()->pending_exception_address(); - Value *pending_exception = builder()->CreateLoad( - pending_exception_addr, "pending_exception"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ(pending_exception, LLVMValue::null()), - no_exception, exception); - - builder()->SetInsertPoint(exception); - builder()->CreateStore(LLVMValue::null(), pending_exception_addr); - SharkTrackingState *saved_state = current_state()->copy(); - handle_exception(pending_exception, attempt_catch); - set_current_state(saved_state); - - builder()->SetInsertPoint(no_exception); -} - -void SharkBlock::handle_exception(Value* exception, bool attempt_catch) -{ - if (attempt_catch && num_exceptions() != 0) { - // Clear the stack and push the exception onto it. - // We do this now to protect it across the VM call - // we may be about to make. - while (xstack_depth()) - pop(); - push(SharkValue::create_jobject(exception)); - - int *indexes = NEW_RESOURCE_ARRAY(int, num_exceptions()); - bool has_catch_all = false; - - ciExceptionHandlerStream eh_iter(target(), bci()); - for (int i = 0; i < num_exceptions(); i++, eh_iter.next()) { - ciExceptionHandler* handler = eh_iter.handler(); - - if (handler->is_catch_all()) { - assert(i == num_exceptions() - 1, "catch-all should be last"); - has_catch_all = true; - } - else { - indexes[i] = handler->catch_klass_index(); - } - } - - int num_options = num_exceptions(); - if (has_catch_all) - num_options--; - - // Drop into the runtime if there are non-catch-all options - if (num_options > 0) { - Value *options = builder()->CreateAlloca( - ArrayType::get(SharkType::jint_type(), num_options), - LLVMValue::jint_constant(1)); - - for (int i = 0; i < num_options; i++) - builder()->CreateStore( - LLVMValue::jint_constant(indexes[i]), - builder()->CreateStructGEP(options, i)); - - Value *index = call_vm_nocheck( - SharkRuntime::find_exception_handler(), - builder()->CreateStructGEP(options, 0), - LLVMValue::jint_constant(num_options)); - check_pending_exception(false); - - // Jump to the exception handler, if found - BasicBlock *no_handler = function()->CreateBlock("no_handler"); - SwitchInst *switchinst = builder()->CreateSwitch( - index, no_handler, num_options); - - for (int i = 0; i < num_options; i++) { - SharkBlock* handler = this->exception(i); - - switchinst->addCase( - LLVMValue::jint_constant(i), - handler->entry_block()); - - handler->add_incoming(current_state()); - } - - builder()->SetInsertPoint(no_handler); - } - - // No specific handler exists, but maybe there's a catch-all - if (has_catch_all) { - SharkBlock* handler = this->exception(num_options); - - builder()->CreateBr(handler->entry_block()); - handler->add_incoming(current_state()); - return; - } - } - - // No exception handler was found; unwind and return - handle_return(T_VOID, exception); -} - -void SharkBlock::add_safepoint() -{ - BasicBlock *orig_block = builder()->GetInsertBlock(); - SharkState *orig_state = current_state()->copy(); - - BasicBlock *do_safepoint = function()->CreateBlock("do_safepoint"); - BasicBlock *safepointed = function()->CreateBlock("safepointed"); - - Value *state = builder()->CreateLoad( - builder()->CreateIntToPtr( - builder()->pointer_constant(SafepointSynchronize::address_of_state()), - PointerType::getUnqual(SharkType::jint_type())), - "state"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ( - state, - LLVMValue::jint_constant(SafepointSynchronize::_synchronizing)), - do_safepoint, safepointed); - - builder()->SetInsertPoint(do_safepoint); - call_vm(SharkRuntime::safepoint()); - BasicBlock *safepointed_block = builder()->GetInsertBlock(); - builder()->CreateBr(safepointed); - - builder()->SetInsertPoint(safepointed); - current_state()->merge(orig_state, orig_block, safepointed_block); -} - -void SharkBlock::call_register_finalizer(Value *receiver) -{ - BasicBlock *orig_block = builder()->GetInsertBlock(); - SharkState *orig_state = current_state()->copy(); - - BasicBlock *do_call = function()->CreateBlock("has_finalizer"); - BasicBlock *done = function()->CreateBlock("done"); - - Value *klass = builder()->CreateValueOfStructEntry( - receiver, - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::jobject_type(), - "klass"); - - Value *klass_part = builder()->CreateAddressOfStructEntry( - klass, - in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()), - SharkType::klass_type(), - "klass_part"); - - Value *access_flags = builder()->CreateValueOfStructEntry( - klass_part, - in_ByteSize(Klass::access_flags_offset_in_bytes()), - SharkType::jint_type(), - "access_flags"); - - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateAnd( - access_flags, - LLVMValue::jint_constant(JVM_ACC_HAS_FINALIZER)), - LLVMValue::jint_constant(0)), - do_call, done); - - builder()->SetInsertPoint(do_call); - call_vm(SharkRuntime::register_finalizer(), receiver); - BasicBlock *branch_block = builder()->GetInsertBlock(); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - current_state()->merge(orig_state, orig_block, branch_block); -} - -void SharkBlock::handle_return(BasicType type, Value* exception) -{ - assert (exception == NULL || type == T_VOID, "exception OR result, please"); - - if (exception) - builder()->CreateStore(exception, function()->exception_slot()); - - release_locked_monitors(); - if (target()->is_synchronized()) - release_method_lock(); - - if (exception) { - exception = builder()->CreateLoad(function()->exception_slot()); - builder()->CreateStore(exception, function()->pending_exception_address()); - } - - Value *result_addr = function()->CreatePopFrame(type2size[type]); - if (type != T_VOID) { - SharkValue *result = pop(); - -#ifdef ASSERT - switch (result->basic_type()) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_SHORT: - assert(type == T_INT, "type mismatch"); - break; - - case T_ARRAY: - assert(type == T_OBJECT, "type mismatch"); - break; - - default: - assert(result->basic_type() == type, "type mismatch"); - } -#endif // ASSERT - - builder()->CreateStore( - result->generic_value(), - builder()->CreateIntToPtr( - result_addr, - PointerType::getUnqual(SharkType::to_stackType(type)))); - } - - builder()->CreateRetVoid(); -} - -void SharkBlock::release_locked_monitors() -{ - int base = target()->is_synchronized(); - for (int i = function()->monitor_count() - 1; i >= base; i--) { - BasicBlock *locked = function()->CreateBlock("locked"); - BasicBlock *unlocked = function()->CreateBlock("unlocked"); - - Value *object = function()->monitor(i)->object(); - builder()->CreateCondBr( - builder()->CreateICmpNE(object, LLVMValue::null()), - locked, unlocked); - - builder()->SetInsertPoint(locked); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - builder()->SetInsertPoint(unlocked); - } } -void SharkBlock::do_ldc() -{ - SharkValue *value = SharkValue::from_ciConstant(iter()->get_constant()); - if (value == NULL) { - SharkConstantPool constants(this); - - BasicBlock *resolved = function()->CreateBlock("resolved"); - BasicBlock *resolved_class = function()->CreateBlock("resolved_class"); - BasicBlock *unresolved = function()->CreateBlock("unresolved"); - BasicBlock *unknown = function()->CreateBlock("unknown"); - BasicBlock *done = function()->CreateBlock("done"); - - SwitchInst *switchinst = builder()->CreateSwitch( - constants.tag_at(iter()->get_constant_index()), - unknown, 5); - - switchinst->addCase( - LLVMValue::jbyte_constant(JVM_CONSTANT_String), resolved); - switchinst->addCase( - LLVMValue::jbyte_constant(JVM_CONSTANT_Class), resolved_class); - switchinst->addCase( - LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedString), unresolved); - switchinst->addCase( - LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClass), unresolved); - switchinst->addCase( - LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClassInError), - unresolved); - - builder()->SetInsertPoint(resolved); - Value *resolved_value = constants.object_at(iter()->get_constant_index()); - builder()->CreateBr(done); - - builder()->SetInsertPoint(resolved_class); - Value *resolved_class_value - = constants.object_at(iter()->get_constant_index()); - resolved_class_value - = builder()->CreatePtrToInt(resolved_class_value, - SharkType::intptr_type()); - resolved_class_value - = (builder()->CreateAdd - (resolved_class_value, - (LLVMValue::intptr_constant - (klassOopDesc::klass_part_offset_in_bytes() - + Klass::java_mirror_offset_in_bytes())))); - resolved_class_value - // FIXME: We need a memory barrier before this load. - = (builder()->CreateLoad - (builder()->CreateIntToPtr - (resolved_class_value, - PointerType::getUnqual(SharkType::jobject_type())))); - builder()->CreateBr(done); - - builder()->SetInsertPoint(unresolved); - builder()->CreateUnimplemented(__FILE__, __LINE__); - Value *unresolved_value = LLVMValue::null(); - builder()->CreateBr(done); - - builder()->SetInsertPoint(unknown); - builder()->CreateShouldNotReachHere(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - builder()->SetInsertPoint(done); - PHINode *phi = builder()->CreatePHI(SharkType::jobject_type(), "constant"); - phi->addIncoming(resolved_value, resolved); - phi->addIncoming(resolved_class_value, resolved_class); - phi->addIncoming(unresolved_value, unresolved); - value = SharkValue::create_jobject(phi); - } - push(value); -} - -void SharkBlock::do_arraylength() -{ - SharkValue *array = pop(); - check_null(array); - Value *length = builder()->CreateArrayLength(array->jarray_value()); - push(SharkValue::create_jint(length)); -} - -void SharkBlock::do_aload(BasicType basic_type) -{ - SharkValue *index = pop(); - SharkValue *array = pop(); - - assert(array->type()->is_array_klass(), "should be"); - ciType *element_type = ((ciArrayKlass *) array->type())->element_type(); - assert((element_type->basic_type() == T_BOOLEAN && basic_type == T_BYTE) || - (element_type->basic_type() == T_ARRAY && basic_type == T_OBJECT) || - (element_type->basic_type() == basic_type), "type mismatch"); - - check_null(array); - check_bounds(array, index); - - Value *value = builder()->CreateLoad( - builder()->CreateArrayAddress( - array->jarray_value(), basic_type, index->jint_value())); - - const Type *stack_type = SharkType::to_stackType(basic_type); - if (value->getType() != stack_type) - value = builder()->CreateIntCast(value, stack_type, basic_type != T_CHAR); - - switch (basic_type) { - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - push(SharkValue::create_jint(value)); - break; - - case T_LONG: - push(SharkValue::create_jlong(value)); - break; - - case T_FLOAT: - push(SharkValue::create_jfloat(value)); - break; - - case T_DOUBLE: - push(SharkValue::create_jdouble(value)); - break; - - case T_OBJECT: - push(SharkValue::create_generic(element_type, value)); - break; - - default: - tty->print_cr("Unhandled type %s", type2name(basic_type)); - ShouldNotReachHere(); - } -} - -void SharkBlock::do_astore(BasicType basic_type) -{ - SharkValue *svalue = pop(); - SharkValue *index = pop(); - SharkValue *array = pop(); - - assert(array->type()->is_array_klass(), "should be"); - ciType *element_type = ((ciArrayKlass *) array->type())->element_type(); - assert((element_type->basic_type() == T_BOOLEAN && basic_type == T_BYTE) || - (element_type->basic_type() == T_ARRAY && basic_type == T_OBJECT) || - (element_type->basic_type() == basic_type), "type mismatch"); - - check_null(array); - check_bounds(array, index); - - Value *value; - switch (basic_type) { - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - value = svalue->jint_value(); - break; - - case T_LONG: - value = svalue->jlong_value(); - break; - - case T_FLOAT: - value = svalue->jfloat_value(); - break; - - case T_DOUBLE: - value = svalue->jdouble_value(); - break; - - case T_OBJECT: - value = svalue->jobject_value(); - // XXX assignability check - break; - - default: - tty->print_cr("Unhandled type %s", type2name(basic_type)); - ShouldNotReachHere(); - } - - const Type *array_type = SharkType::to_arrayType(basic_type); - if (value->getType() != array_type) - value = builder()->CreateIntCast(value, array_type, basic_type != T_CHAR); - - Value *addr = builder()->CreateArrayAddress( - array->jarray_value(), basic_type, index->jint_value(), "addr"); - - builder()->CreateStore(value, addr); - - if (!element_type->is_primitive_type()) - builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); -} - -void SharkBlock::do_div_or_rem(bool is_long, bool is_rem) +SharkState* SharkBlock::initial_current_state() { - SharkValue *sb = pop(); - SharkValue *sa = pop(); - - check_divide_by_zero(sb); - - Value *a, *b, *p, *q; - if (is_long) { - a = sa->jlong_value(); - b = sb->jlong_value(); - p = LLVMValue::jlong_constant(0x8000000000000000LL); - q = LLVMValue::jlong_constant(-1); - } - else { - a = sa->jint_value(); - b = sb->jint_value(); - p = LLVMValue::jint_constant(0x80000000); - q = LLVMValue::jint_constant(-1); - } - - BasicBlock *special_case = function()->CreateBlock("special_case"); - BasicBlock *general_case = function()->CreateBlock("general_case"); - BasicBlock *done = function()->CreateBlock("done"); - - builder()->CreateCondBr( - builder()->CreateAnd( - builder()->CreateICmpEQ(a, p), - builder()->CreateICmpEQ(b, q)), - special_case, general_case); - - builder()->SetInsertPoint(special_case); - Value *special_result; - if (is_rem) { - if (is_long) - special_result = LLVMValue::jlong_constant(0); - else - special_result = LLVMValue::jint_constant(0); - } - else { - special_result = a; - } - builder()->CreateBr(done); - - builder()->SetInsertPoint(general_case); - Value *general_result; - if (is_rem) - general_result = builder()->CreateSRem(a, b); - else - general_result = builder()->CreateSDiv(a, b); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *result; - if (is_long) - result = builder()->CreatePHI(SharkType::jlong_type(), "result"); - else - result = builder()->CreatePHI(SharkType::jint_type(), "result"); - result->addIncoming(special_result, special_case); - result->addIncoming(general_result, general_case); - - if (is_long) - push(SharkValue::create_jlong(result)); - else - push(SharkValue::create_jint(result)); -} - -void SharkBlock::do_field_access(bool is_get, bool is_field, ciField* field) -{ - if (field == NULL) { - bool will_link; - field = iter()->get_field(will_link); - assert(will_link, "typeflow responsibility"); - - // Check the bytecode matches the field - if (is_field == field->is_static()) - Unimplemented(); - } - - // Pop the value off the stack where necessary - SharkValue *value = NULL; - if (!is_get) - value = pop(); - - // Find the object we're accessing, if necessary - Value *object = NULL; - if (is_field) { - SharkValue *value = pop(); - check_null(value); - object = value->generic_value(); - } - if (is_get && field->is_constant()) { - value = SharkValue::from_ciConstant(field->constant_value()); - } - if (!is_get || value == NULL) { - if (!is_field) { - SharkConstantPool constants(this); - Value *cache = constants.cache_entry_at(iter()->get_field_index()); - - object = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f1_offset(), - SharkType::jobject_type(), - "object"); - } - - BasicType basic_type = field->type()->basic_type(); - const Type *stack_type = SharkType::to_stackType(basic_type); - const Type *field_type = SharkType::to_arrayType(basic_type); - - Value *addr = builder()->CreateAddressOfStructEntry( - object, in_ByteSize(field->offset_in_bytes()), - PointerType::getUnqual(field_type), - "addr"); - - // Do the access - if (is_get) { - Value *field_value = builder()->CreateLoad(addr); - - if (field_type != stack_type) - field_value = builder()->CreateIntCast( - field_value, stack_type, basic_type != T_CHAR); - - value = SharkValue::create_generic(field->type(), field_value); - } - else { - Value *field_value = value->generic_value(); - - if (field_type != stack_type) - field_value = builder()->CreateIntCast( - field_value, field_type, basic_type != T_CHAR); - - builder()->CreateStore(field_value, addr); - - if (!field->type()->is_primitive_type()) - builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); - - if (field->is_volatile()) - builder()->CreateMemoryBarrier(SharkBuilder::BARRIER_STORELOAD); - } - } - - // Push the value onto the stack where necessary - if (is_get) - push(value); -} - -void SharkBlock::do_lcmp() -{ - Value *b = pop()->jlong_value(); - Value *a = pop()->jlong_value(); - - BasicBlock *ne = function()->CreateBlock("lcmp_ne"); - BasicBlock *lt = function()->CreateBlock("lcmp_lt"); - BasicBlock *gt = function()->CreateBlock("lcmp_gt"); - BasicBlock *done = function()->CreateBlock("done"); - - BasicBlock *eq = builder()->GetInsertBlock(); - builder()->CreateCondBr(builder()->CreateICmpEQ(a, b), done, ne); - - builder()->SetInsertPoint(ne); - builder()->CreateCondBr(builder()->CreateICmpSLT(a, b), lt, gt); - - builder()->SetInsertPoint(lt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(gt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); - result->addIncoming(LLVMValue::jint_constant(-1), lt); - result->addIncoming(LLVMValue::jint_constant(0), eq); - result->addIncoming(LLVMValue::jint_constant(1), gt); - - push(SharkValue::create_jint(result)); -} - -void SharkBlock::do_fcmp(bool is_double, bool unordered_is_greater) -{ - Value *a, *b; - if (is_double) { - b = pop()->jdouble_value(); - a = pop()->jdouble_value(); - } - else { - b = pop()->jfloat_value(); - a = pop()->jfloat_value(); - } - - BasicBlock *ordered = function()->CreateBlock("ordered"); - BasicBlock *ge = function()->CreateBlock("fcmp_ge"); - BasicBlock *lt = function()->CreateBlock("fcmp_lt"); - BasicBlock *eq = function()->CreateBlock("fcmp_eq"); - BasicBlock *gt = function()->CreateBlock("fcmp_gt"); - BasicBlock *done = function()->CreateBlock("done"); - - builder()->CreateCondBr( - builder()->CreateFCmpUNO(a, b), - unordered_is_greater ? gt : lt, ordered); - - builder()->SetInsertPoint(ordered); - builder()->CreateCondBr(builder()->CreateFCmpULT(a, b), lt, ge); - - builder()->SetInsertPoint(ge); - builder()->CreateCondBr(builder()->CreateFCmpUGT(a, b), gt, eq); - - builder()->SetInsertPoint(lt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(gt); - builder()->CreateBr(done); - - builder()->SetInsertPoint(eq); - builder()->CreateBr(done); - - builder()->SetInsertPoint(done); - PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); - result->addIncoming(LLVMValue::jint_constant(-1), lt); - result->addIncoming(LLVMValue::jint_constant(0), eq); - result->addIncoming(LLVMValue::jint_constant(1), gt); - - push(SharkValue::create_jint(result)); -} - -void SharkBlock::do_if(ICmpInst::Predicate p, SharkValue *b, SharkValue *a) -{ - Value *llvm_a, *llvm_b; - if (a->is_jobject()) { - llvm_a = a->intptr_value(builder()); - llvm_b = b->intptr_value(builder()); - } - else { - llvm_a = a->jint_value(); - llvm_b = b->jint_value(); - } - - builder()->CreateCondBr( - builder()->CreateICmp(p, llvm_a, llvm_b), - successor(ciTypeFlow::IF_TAKEN)->entry_block(), - successor(ciTypeFlow::IF_NOT_TAKEN)->entry_block()); + return new SharkState(entry_state()); } int SharkBlock::switch_default_dest() @@ -1741,1036 +895,340 @@ } } -void SharkBlock::do_switch() -{ - int len = switch_table_length(); - - SharkBlock *dest_block = successor(ciTypeFlow::SWITCH_DEFAULT); - SwitchInst *switchinst = builder()->CreateSwitch( - pop()->jint_value(), dest_block->entry_block(), len); - dest_block->add_incoming(current_state()); - - for (int i = 0; i < len; i++) { - int dest_bci = switch_dest(i); - if (dest_bci != switch_default_dest()) { - dest_block = bci_successor(dest_bci); - switchinst->addCase( - LLVMValue::jint_constant(switch_key(i)), - dest_block->entry_block()); - dest_block->add_incoming(current_state()); - } - } -} - -// Figure out what type of call this is. -// - Direct calls are where the callee is fixed. -// - Interface and Virtual calls require lookup at runtime. -// NB some invokevirtuals can be resolved to direct calls. -SharkBlock::CallType SharkBlock::get_call_type(ciMethod* method) -{ - if (bc() == Bytecodes::_invokeinterface) - return CALL_INTERFACE; - else if (bc() == Bytecodes::_invokevirtual && !method->is_final_method()) - return CALL_VIRTUAL; - else - return CALL_DIRECT; -} - -Value *SharkBlock::get_callee(CallType call_type, - ciMethod* method, - SharkValue* receiver) +void SharkBlock::do_div_or_rem(bool is_long, bool is_rem) { - switch (call_type) { - case CALL_DIRECT: - return get_direct_callee(method); - case CALL_VIRTUAL: - return get_virtual_callee(receiver, method); - case CALL_INTERFACE: - return get_interface_callee(receiver); - default: - ShouldNotReachHere(); - } -} + SharkValue *sb = pop(); + SharkValue *sa = pop(); + + check_divide_by_zero(sb); -// Direct calls can be made when the callee is fixed. -// invokestatic and invokespecial are always direct; -// invokevirtual is direct in some circumstances. -Value *SharkBlock::get_direct_callee(ciMethod* method) -{ - SharkConstantPool constants(this); - Value *cache = constants.cache_entry_at(iter()->get_method_index()); - return builder()->CreateValueOfStructEntry( - cache, - bc() == Bytecodes::_invokevirtual ? - ConstantPoolCacheEntry::f2_offset() : - ConstantPoolCacheEntry::f1_offset(), - SharkType::methodOop_type(), - "callee"); -} - -// Non-direct virtual calls are handled here -Value *SharkBlock::get_virtual_callee(SharkValue *receiver, ciMethod* method) -{ - Value *klass = builder()->CreateValueOfStructEntry( - receiver->jobject_value(), - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::jobject_type(), - "klass"); - - Value *index; - if (!method->holder()->is_linked()) { - // Yuck, we have to do this one slow :( - // XXX should we trap on this? - NOT_PRODUCT(warning("unresolved invokevirtual in %s", function()->name())); - SharkConstantPool constants(this); - Value *cache = constants.cache_entry_at(iter()->get_method_index()); - index = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f2_offset(), - SharkType::intptr_type(), - "index"); + Value *a, *b, *p, *q; + if (is_long) { + a = sa->jlong_value(); + b = sb->jlong_value(); + p = LLVMValue::jlong_constant(0x8000000000000000LL); + q = LLVMValue::jlong_constant(-1); } else { - index = LLVMValue::intptr_constant(method->vtable_index()); + a = sa->jint_value(); + b = sb->jint_value(); + p = LLVMValue::jint_constant(0x80000000); + q = LLVMValue::jint_constant(-1); } - return builder()->CreateLoad( - builder()->CreateArrayAddress( - klass, - SharkType::methodOop_type(), - vtableEntry::size() * wordSize, - in_ByteSize(instanceKlass::vtable_start_offset() * wordSize), - index), - "callee"); -} - -// Interpreter-style virtual call lookup -Value* SharkBlock::get_virtual_callee(Value *cache, SharkValue *receiver) -{ - BasicBlock *final = function()->CreateBlock("final"); - BasicBlock *not_final = function()->CreateBlock("not_final"); - BasicBlock *got_callee = function()->CreateBlock("got_callee"); - - Value *flags = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::flags_offset(), - SharkType::intptr_type(), - "flags"); - - const int mask = 1 << ConstantPoolCacheEntry::vfinalMethod; - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), - LLVMValue::intptr_constant(0)), - final, not_final); + BasicBlock *ip = builder()->GetBlockInsertionPoint(); + BasicBlock *special_case = builder()->CreateBlock(ip, "special_case"); + BasicBlock *general_case = builder()->CreateBlock(ip, "general_case"); + BasicBlock *done = builder()->CreateBlock(ip, "done"); - // For final methods f2 is the actual address of the method - builder()->SetInsertPoint(final); - Value *final_callee = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f2_offset(), - SharkType::methodOop_type(), - "final_callee"); - builder()->CreateBr(got_callee); - - // For non-final methods f2 is the index into the vtable - builder()->SetInsertPoint(not_final); - Value *klass = builder()->CreateValueOfStructEntry( - receiver->jobject_value(), - in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::jobject_type(), - "klass"); + builder()->CreateCondBr( + builder()->CreateAnd( + builder()->CreateICmpEQ(a, p), + builder()->CreateICmpEQ(b, q)), + special_case, general_case); + + builder()->SetInsertPoint(special_case); + Value *special_result; + if (is_rem) { + if (is_long) + special_result = LLVMValue::jlong_constant(0); + else + special_result = LLVMValue::jint_constant(0); + } + else { + special_result = a; + } + builder()->CreateBr(done); - Value *index = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f2_offset(), - SharkType::intptr_type(), - "index"); + builder()->SetInsertPoint(general_case); + Value *general_result; + if (is_rem) + general_result = builder()->CreateSRem(a, b); + else + general_result = builder()->CreateSDiv(a, b); + builder()->CreateBr(done); - Value *nonfinal_callee = builder()->CreateLoad( - builder()->CreateArrayAddress( - klass, - SharkType::methodOop_type(), - vtableEntry::size() * wordSize, - in_ByteSize(instanceKlass::vtable_start_offset() * wordSize), - index), - "nonfinal_callee"); - builder()->CreateBr(got_callee); + builder()->SetInsertPoint(done); + PHINode *result; + if (is_long) + result = builder()->CreatePHI(SharkType::jlong_type(), "result"); + else + result = builder()->CreatePHI(SharkType::jint_type(), "result"); + result->addIncoming(special_result, special_case); + result->addIncoming(general_result, general_case); - builder()->SetInsertPoint(got_callee); - PHINode *callee = builder()->CreatePHI( - SharkType::methodOop_type(), "callee"); - callee->addIncoming(final_callee, final); - callee->addIncoming(nonfinal_callee, not_final); - - return callee; + if (is_long) + push(SharkValue::create_jlong(result)); + else + push(SharkValue::create_jint(result)); } -// Interpreter-style interface call lookup -Value* SharkBlock::get_interface_callee(SharkValue *receiver) +void SharkBlock::do_field_access(bool is_get, bool is_field) { - SharkConstantPool constants(this); - Value *cache = constants.cache_entry_at(iter()->get_method_index()); - - BasicBlock *hacky = function()->CreateBlock("hacky"); - BasicBlock *normal = function()->CreateBlock("normal"); - BasicBlock *loop = function()->CreateBlock("loop"); - BasicBlock *got_null = function()->CreateBlock("got_null"); - BasicBlock *not_null = function()->CreateBlock("not_null"); - BasicBlock *next = function()->CreateBlock("next"); - BasicBlock *got_entry = function()->CreateBlock("got_entry"); - BasicBlock *got_callee = function()->CreateBlock("got_callee"); - - Value *flags = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::flags_offset(), - SharkType::intptr_type(), - "flags"); - - const int mask = 1 << ConstantPoolCacheEntry::methodInterface; - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), - LLVMValue::intptr_constant(0)), - hacky, normal); + bool will_link; + ciField *field = iter()->get_field(will_link); + assert(will_link, "typeflow responsibility"); - // Workaround for the case where we encounter an invokeinterface, - // but should really have an invokevirtual since the resolved - // method is a virtual method in java.lang.Object. This is a - // corner case in the spec but is presumably legal, and while - // javac does not generate this code there's no reason it could - // not be produced by a compliant java compiler. See - // cpCacheOop.cpp for more details. - builder()->SetInsertPoint(hacky); - Value *hacky_callee = get_virtual_callee(cache, receiver); - BasicBlock *got_hacky = builder()->GetInsertBlock(); - builder()->CreateBr(got_callee); - - // Locate the receiver's itable - builder()->SetInsertPoint(normal); - Value *object_klass = builder()->CreateValueOfStructEntry( - receiver->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::jobject_type(), - "object_klass"); - - Value *vtable_start = builder()->CreateAdd( - builder()->CreatePtrToInt(object_klass, SharkType::intptr_type()), - LLVMValue::intptr_constant( - instanceKlass::vtable_start_offset() * HeapWordSize), - "vtable_start"); - - Value *vtable_length = builder()->CreateValueOfStructEntry( - object_klass, - in_ByteSize(instanceKlass::vtable_length_offset() * HeapWordSize), - SharkType::jint_type(), - "vtable_length"); - vtable_length = - builder()->CreateIntCast(vtable_length, SharkType::intptr_type(), false); + // Check the bytecode matches the field + if (is_field == field->is_static()) + Unimplemented(); - bool needs_aligning = HeapWordsPerLong > 1; - const char *itable_start_name = "itable_start"; - Value *itable_start = builder()->CreateAdd( - vtable_start, - builder()->CreateShl( - vtable_length, - LLVMValue::intptr_constant(exact_log2(vtableEntry::size() * wordSize))), - needs_aligning ? "" : itable_start_name); - if (needs_aligning) - itable_start = builder()->CreateAlign( - itable_start, BytesPerLong, itable_start_name); - - // Locate this interface's entry in the table - Value *iklass = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f1_offset(), - SharkType::jobject_type(), - "iklass"); - - builder()->CreateBr(loop); - builder()->SetInsertPoint(loop); - PHINode *itable_entry_addr = builder()->CreatePHI( - SharkType::intptr_type(), "itable_entry_addr"); - itable_entry_addr->addIncoming(itable_start, normal); - - Value *itable_entry = builder()->CreateIntToPtr( - itable_entry_addr, SharkType::itableOffsetEntry_type(), "itable_entry"); - - Value *itable_iklass = builder()->CreateValueOfStructEntry( - itable_entry, - in_ByteSize(itableOffsetEntry::interface_offset_in_bytes()), - SharkType::jobject_type(), - "itable_iklass"); + // Pop the value off the stack where necessary + SharkValue *value = NULL; + if (!is_get) + value = pop(); - builder()->CreateCondBr( - builder()->CreateICmpEQ(itable_iklass, LLVMValue::null()), - got_null, not_null); - - // A null entry means that the class doesn't implement the - // interface, and wasn't the same as the class checked when - // the interface was resolved. - builder()->SetInsertPoint(got_null); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - builder()->SetInsertPoint(not_null); - builder()->CreateCondBr( - builder()->CreateICmpEQ(itable_iklass, iklass), - got_entry, next); - - builder()->SetInsertPoint(next); - Value *next_entry = builder()->CreateAdd( - itable_entry_addr, - LLVMValue::intptr_constant(itableOffsetEntry::size() * wordSize)); - builder()->CreateBr(loop); - itable_entry_addr->addIncoming(next_entry, next); - - // Locate the method pointer - builder()->SetInsertPoint(got_entry); - Value *offset = builder()->CreateValueOfStructEntry( - itable_entry, - in_ByteSize(itableOffsetEntry::offset_offset_in_bytes()), - SharkType::jint_type(), - "offset"); - offset = - builder()->CreateIntCast(offset, SharkType::intptr_type(), false); - - Value *index = builder()->CreateValueOfStructEntry( - cache, ConstantPoolCacheEntry::f2_offset(), - SharkType::intptr_type(), - "index"); + // Find the object we're accessing, if necessary + Value *object = NULL; + if (is_field) { + SharkValue *value = pop(); + check_null(value); + object = value->generic_value(); + } + if (is_get && field->is_constant()) { + value = SharkValue::from_ciConstant(field->constant_value()); + } + if (!is_get || value == NULL) { + if (!is_field) + object = lookup_for_field_access(); - Value *normal_callee = builder()->CreateLoad( - builder()->CreateIntToPtr( - builder()->CreateAdd( - builder()->CreateAdd( - builder()->CreateAdd( - builder()->CreatePtrToInt( - object_klass, SharkType::intptr_type()), - offset), - builder()->CreateShl( - index, - LLVMValue::intptr_constant( - exact_log2(itableMethodEntry::size() * wordSize)))), - LLVMValue::intptr_constant( - itableMethodEntry::method_offset_in_bytes())), - PointerType::getUnqual(SharkType::methodOop_type())), - "normal_callee"); - BasicBlock *got_normal = builder()->GetInsertBlock(); - builder()->CreateBr(got_callee); - - builder()->SetInsertPoint(got_callee); - PHINode *callee = builder()->CreatePHI( - SharkType::methodOop_type(), "callee"); - callee->addIncoming(hacky_callee, got_hacky); - callee->addIncoming(normal_callee, got_normal); - - return callee; -} + BasicType basic_type = field->type()->basic_type(); + const Type *stack_type = SharkType::to_stackType(basic_type); + const Type *field_type = SharkType::to_arrayType(basic_type); + + Value *addr = builder()->CreateAddressOfStructEntry( + object, in_ByteSize(field->offset_in_bytes()), + PointerType::getUnqual(field_type), + "addr"); + + // Do the access + if (is_get) { + Value *field_value = builder()->CreateLoad(addr); -bool SharkBlock::maybe_inline_call(ciMethod *method) -{ - // Quick checks to allow us to bail out fast. We can't inline - // native methods, there's no point inlining abstract ones, and - // monitors aren't allowed because the inlined section has no - // frame to put them in. - if (method->is_native() || - method->is_abstract() || - method->is_synchronized() || - method->has_monitor_bytecodes()) - return false; - - // Inlining empty methods is trivial - if (method->is_empty_method()) { - int desired_stack_depth = xstack_depth() - method->arg_size(); - while (xstack_depth() > desired_stack_depth) - pop(); - - return true; - } - - // We need to scan the bytecode to do any more, so we bail out - // now if the method is too big - if (method->code_size() > 5) - return false; - - // If the holder isn't linked then there isn't a lot we can do - if (!method->holder()->is_linked()) - return false; - - // Inspect the method's code to see if we can inline it. We - // don't use method->is_accessor() because that only spots - // some getfields, whereas we can inline *all* getfields, all - // putfields, and some getstatics too. - address code = method->code(); - switch (method->code_size()) { - case 4: - // getstatic and putstatic will try to look up the receiver - // from the holder's constant pool, which we can't do. Some - // getstatics, however, resolve to constants, and those we - // can do. So we try... - if (code[0] == Bytecodes::_getstatic) - return maybe_inline_accessor(method, false); - break; + if (field_type != stack_type) + field_value = builder()->CreateIntCast( + field_value, stack_type, basic_type != T_CHAR); - case 5: - if (code[0] == Bytecodes::_aload_0 && - (code[1] == Bytecodes::_getfield || - code[1] == Bytecodes::_putfield)) - return maybe_inline_accessor(method, true); - break; - } - return false; -} - -bool SharkBlock::maybe_inline_accessor(ciMethod *method, bool is_field) -{ - if (method->arg_size() != (is_field ? 1 : 0)) { - NOT_PRODUCT(warning("wacky accessor in %s", function()->name())); - return false; - } - - ciBytecodeStream iter(method); - Bytecodes::Code bc; - - if (is_field) { - bc = iter.next(); - assert(bc == Bytecodes::_aload_0, "eh?"); - } - - bool is_get; - bc = iter.next(); - if (is_field) { - assert(bc == Bytecodes::_getfield || bc == Bytecodes::_putfield, "eh?"); - is_get = bc == Bytecodes::_getfield; - } - else { - assert(bc == Bytecodes::_getstatic, "eh?"); - is_get = true; - } + value = SharkValue::create_generic(field->type(), field_value); + } + else { + Value *field_value = value->generic_value(); - bool will_link; - ciField *field = iter.get_field(will_link); - if (!will_link) - return false; - - // We can only inline getstatic if the field resolves to a - // non-oop constant. - if (!is_field) { - if (!field->is_constant()) - return false; - - if (SharkValue::from_ciConstant(field->constant_value()) == NULL) - return false; - } + if (field_type != stack_type) + field_value = builder()->CreateIntCast( + field_value, field_type, basic_type != T_CHAR); - // We mustn't inline if the resolved field is the wrong type, - // because the thrown exception would appear to come from the - // wrong method. - if (is_field == field->is_static()) - return false; - - bc = iter.next(); - if (is_get) { - switch (bc) { - case Bytecodes::_ireturn: - case Bytecodes::_lreturn: - case Bytecodes::_freturn: - case Bytecodes::_dreturn: - case Bytecodes::_areturn: - break; + builder()->CreateStore(field_value, addr); + + if (!field->type()->is_primitive_type()) + builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); - default: - NOT_PRODUCT(warning("wacky accessor in %s", function()->name())); - return false; - } - } - else { - if (bc != Bytecodes::_return) { - NOT_PRODUCT(warning("wacky accessor in %s", function()->name())); - return false; + if (field->is_volatile()) + builder()->CreateMemoryBarrier(SharkBuilder::BARRIER_STORELOAD); } } - bc = iter.next(); - assert(bc == ciBytecodeStream::EOBC(), "eh?"); + // Push the value onto the stack where necessary + if (is_get) + push(value); +} + +void SharkBlock::do_lcmp() +{ + Value *b = pop()->jlong_value(); + Value *a = pop()->jlong_value(); + + BasicBlock *ip = builder()->GetBlockInsertionPoint(); + BasicBlock *ne = builder()->CreateBlock(ip, "lcmp_ne"); + BasicBlock *lt = builder()->CreateBlock(ip, "lcmp_lt"); + BasicBlock *gt = builder()->CreateBlock(ip, "lcmp_gt"); + BasicBlock *done = builder()->CreateBlock(ip, "done"); + + BasicBlock *eq = builder()->GetInsertBlock(); + builder()->CreateCondBr(builder()->CreateICmpEQ(a, b), done, ne); + + builder()->SetInsertPoint(ne); + builder()->CreateCondBr(builder()->CreateICmpSLT(a, b), lt, gt); + + builder()->SetInsertPoint(lt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(gt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(-1), lt); + result->addIncoming(LLVMValue::jint_constant(0), eq); + result->addIncoming(LLVMValue::jint_constant(1), gt); + + push(SharkValue::create_jint(result)); +} + +void SharkBlock::do_fcmp(bool is_double, bool unordered_is_greater) +{ + Value *a, *b; + if (is_double) { + b = pop()->jdouble_value(); + a = pop()->jdouble_value(); + } + else { + b = pop()->jfloat_value(); + a = pop()->jfloat_value(); + } + + BasicBlock *ip = builder()->GetBlockInsertionPoint(); + BasicBlock *ordered = builder()->CreateBlock(ip, "ordered"); + BasicBlock *ge = builder()->CreateBlock(ip, "fcmp_ge"); + BasicBlock *lt = builder()->CreateBlock(ip, "fcmp_lt"); + BasicBlock *eq = builder()->CreateBlock(ip, "fcmp_eq"); + BasicBlock *gt = builder()->CreateBlock(ip, "fcmp_gt"); + BasicBlock *done = builder()->CreateBlock(ip, "done"); + + builder()->CreateCondBr( + builder()->CreateFCmpUNO(a, b), + unordered_is_greater ? gt : lt, ordered); + + builder()->SetInsertPoint(ordered); + builder()->CreateCondBr(builder()->CreateFCmpULT(a, b), lt, ge); + + builder()->SetInsertPoint(ge); + builder()->CreateCondBr(builder()->CreateFCmpUGT(a, b), gt, eq); + + builder()->SetInsertPoint(lt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(gt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(eq); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(-1), lt); + result->addIncoming(LLVMValue::jint_constant(0), eq); + result->addIncoming(LLVMValue::jint_constant(1), gt); - // For field accesses we need to null check the receiver before - // entering the inlined section. For the majority of accessors - // this has already been done (in do_call) but if the accessor - // was invoked by invokestatic (eg synthetic accessors) then it - // may not have been checked and do_field_access will try to do - // it and fail. - if (is_field) { - if (!xstack(0)->zero_checked()) - return false; - } - - current_state()->enter_inlined_section(); - do_field_access(is_get, is_field, field); - current_state()->leave_inlined_section(); - return true; + push(SharkValue::create_jint(result)); +} + +void SharkBlock::emit_IR() +{ + ShouldNotCallThis(); +} + +SharkState* SharkBlock::entry_state() +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_zero_check(SharkValue* value) +{ + ShouldNotCallThis(); +} + +void SharkBlock::add_safepoint() +{ + ShouldNotCallThis(); +} + +Value* SharkBlock::lookup_for_ldc() +{ + ShouldNotCallThis(); +} + +Value* SharkBlock::lookup_for_field_access() +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_arraylength() +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_aload(BasicType basic_type) +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_astore(BasicType basic_type) +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_return(BasicType type) +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_athrow() +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_goto() +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_jsr() +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_ret() +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_if(ICmpInst::Predicate p, SharkValue* b, SharkValue* a) +{ + ShouldNotCallThis(); +} + +void SharkBlock::do_switch() +{ + ShouldNotCallThis(); } void SharkBlock::do_call() { - bool will_link; - ciMethod *method = iter()->get_method(will_link); - assert(will_link, "typeflow responsibility"); - - // Figure out what type of call this is - CallType call_type = get_call_type(method); - - // Find the receiver in the stack. This has to happen - // before we try to inline, because nothing in the inlined - // code can decache (which check_null needs to do for the - // VM call to throw the NullPointerException). Once we've - // checked, the repeated null check elimination stuff does - // the work for us. - SharkValue *receiver = NULL; - if (bc() != Bytecodes::_invokestatic) { - receiver = xstack(method->arg_size() - 1); - check_null(receiver); - } - - // Try to inline the call - if (call_type == CALL_DIRECT) { - if (maybe_inline_call(method)) - return; - } - - // Find the method we are calling - Value *callee = get_callee(call_type, method, receiver); - - // Load the SharkEntry from the callee - Value *base_pc = builder()->CreateValueOfStructEntry( - callee, methodOopDesc::from_interpreted_offset(), - SharkType::intptr_type(), - "base_pc"); - - // Load the entry point from the SharkEntry - Value *entry_point = builder()->CreateLoad( - builder()->CreateIntToPtr( - builder()->CreateAdd( - base_pc, - LLVMValue::intptr_constant(in_bytes(ZeroEntry::entry_point_offset()))), - PointerType::getUnqual( - PointerType::getUnqual(SharkType::entry_point_type()))), - "entry_point"); - - // Make the call - current_state()->decache_for_Java_call(method); - builder()->CreateCall3(entry_point, callee, base_pc, thread()); - current_state()->cache_after_Java_call(method); - - // Check for pending exceptions - check_pending_exception(); + ShouldNotCallThis(); } void SharkBlock::do_instance_check() { - // Leave the object on the stack until after all the VM calls - assert(xstack(0)->is_jobject(), "should be"); - - ciKlass *klass = NULL; - if (bc() == Bytecodes::_checkcast) { - bool will_link; - klass = iter()->get_klass(will_link); - if (!will_link) { - // XXX why is this not typeflow's responsibility? - NOT_PRODUCT(warning("unresolved checkcast in %s", function()->name())); - klass = (ciKlass *) xstack(0)->type(); - } - } - - BasicBlock *not_null = function()->CreateBlock("not_null"); - BasicBlock *fast_path = function()->CreateBlock("fast_path"); - BasicBlock *slow_path = function()->CreateBlock("slow_path"); - BasicBlock *got_klass = function()->CreateBlock("got_klass"); - BasicBlock *subtype_check = function()->CreateBlock("subtype_check"); - BasicBlock *is_instance = function()->CreateBlock("is_instance"); - BasicBlock *not_instance = function()->CreateBlock("not_instance"); - BasicBlock *merge1 = function()->CreateBlock("merge1"); - BasicBlock *merge2 = function()->CreateBlock("merge2"); - - enum InstanceCheckStates { - IC_IS_NULL, - IC_IS_INSTANCE, - IC_NOT_INSTANCE, - }; - - // Null objects aren't instances of anything - builder()->CreateCondBr( - builder()->CreateICmpEQ(xstack(0)->jobject_value(), LLVMValue::null()), - merge2, not_null); - BasicBlock *null_block = builder()->GetInsertBlock(); - SharkState *null_state = current_state()->copy(); - - // Get the class we're checking against - builder()->SetInsertPoint(not_null); - SharkConstantPool constants(this); - Value *tag = constants.tag_at(iter()->get_klass_index()); - builder()->CreateCondBr( - builder()->CreateOr( - builder()->CreateICmpEQ( - tag, LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClass)), - builder()->CreateICmpEQ( - tag, LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClassInError))), - slow_path, fast_path); - - // The fast path - builder()->SetInsertPoint(fast_path); - BasicBlock *fast_block = builder()->GetInsertBlock(); - SharkState *fast_state = current_state()->copy(); - Value *fast_klass = constants.object_at(iter()->get_klass_index()); - builder()->CreateBr(got_klass); - - // The slow path - builder()->SetInsertPoint(slow_path); - call_vm( - SharkRuntime::resolve_klass(), - LLVMValue::jint_constant(iter()->get_klass_index())); - Value *slow_klass = function()->CreateGetVMResult(); - BasicBlock *slow_block = builder()->GetInsertBlock(); - builder()->CreateBr(got_klass); - - // We have the class to test against - builder()->SetInsertPoint(got_klass); - current_state()->merge(fast_state, fast_block, slow_block); - PHINode *check_klass = builder()->CreatePHI( - SharkType::jobject_type(), "check_klass"); - check_klass->addIncoming(fast_klass, fast_block); - check_klass->addIncoming(slow_klass, slow_block); - - // Get the class of the object being tested - Value *object_klass = builder()->CreateValueOfStructEntry( - xstack(0)->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), - SharkType::jobject_type(), - "object_klass"); - - // Perform the check - builder()->CreateCondBr( - builder()->CreateICmpEQ(check_klass, object_klass), - is_instance, subtype_check); - - builder()->SetInsertPoint(subtype_check); - builder()->CreateCondBr( - builder()->CreateICmpNE( - builder()->CreateCall2( - SharkRuntime::is_subtype_of(), check_klass, object_klass), - LLVMValue::jbyte_constant(0)), - is_instance, not_instance); - - builder()->SetInsertPoint(is_instance); - builder()->CreateBr(merge1); - - builder()->SetInsertPoint(not_instance); - builder()->CreateBr(merge1); - - // First merge - builder()->SetInsertPoint(merge1); - PHINode *nonnull_result = builder()->CreatePHI( - SharkType::jint_type(), "nonnull_result"); - nonnull_result->addIncoming( - LLVMValue::jint_constant(IC_IS_INSTANCE), is_instance); - nonnull_result->addIncoming( - LLVMValue::jint_constant(IC_NOT_INSTANCE), not_instance); - BasicBlock *nonnull_block = builder()->GetInsertBlock(); - builder()->CreateBr(merge2); - - // Second merge - builder()->SetInsertPoint(merge2); - current_state()->merge(null_state, null_block, nonnull_block); - PHINode *result = builder()->CreatePHI( - SharkType::jint_type(), "result"); - result->addIncoming(LLVMValue::jint_constant(IC_IS_NULL), null_block); - result->addIncoming(nonnull_result, nonnull_block); - - // We can finally pop the object! - Value *object = pop()->jobject_value(); - - // Handle the result - if (bc() == Bytecodes::_checkcast) { - BasicBlock *failure = function()->CreateBlock("failure"); - BasicBlock *success = function()->CreateBlock("success"); - - builder()->CreateCondBr( - builder()->CreateICmpNE( - result, LLVMValue::jint_constant(IC_NOT_INSTANCE)), - success, failure); - - builder()->SetInsertPoint(failure); - builder()->CreateUnimplemented(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - builder()->SetInsertPoint(success); - push(SharkValue::create_generic(klass, object)); - } - else { - push( - SharkValue::create_jint( - builder()->CreateIntCast( - builder()->CreateICmpEQ( - result, LLVMValue::jint_constant(IC_IS_INSTANCE)), - SharkType::jint_type(), false))); - } + ShouldNotCallThis(); } void SharkBlock::do_new() { - bool will_link; - ciInstanceKlass* klass = iter()->get_klass(will_link)->as_instance_klass(); - assert(will_link, "typeflow responsibility"); - - BasicBlock *tlab_alloc = NULL; - BasicBlock *got_tlab = NULL; - BasicBlock *heap_alloc = NULL; - BasicBlock *retry = NULL; - BasicBlock *got_heap = NULL; - BasicBlock *initialize = NULL; - BasicBlock *got_fast = NULL; - BasicBlock *slow_alloc_and_init = NULL; - BasicBlock *got_slow = NULL; - BasicBlock *push_object = NULL; - - SharkState *fast_state = NULL; - - Value *tlab_object = NULL; - Value *heap_object = NULL; - Value *fast_object = NULL; - Value *slow_object = NULL; - Value *object = NULL; - - SharkConstantPool constants(this); - - // The fast path - if (!Klass::layout_helper_needs_slow_path(klass->layout_helper())) { - if (UseTLAB) { - tlab_alloc = function()->CreateBlock("tlab_alloc"); - got_tlab = function()->CreateBlock("got_tlab"); - } - heap_alloc = function()->CreateBlock("heap_alloc"); - retry = function()->CreateBlock("retry"); - got_heap = function()->CreateBlock("got_heap"); - initialize = function()->CreateBlock("initialize"); - slow_alloc_and_init = function()->CreateBlock("slow_alloc_and_init"); - push_object = function()->CreateBlock("push_object"); - - builder()->CreateCondBr( - builder()->CreateICmpEQ( - constants.tag_at(iter()->get_klass_index()), - LLVMValue::jbyte_constant(JVM_CONSTANT_Class)), - UseTLAB ? tlab_alloc : heap_alloc, slow_alloc_and_init); - - size_t size_in_bytes = klass->size_helper() << LogHeapWordSize; - - // Thread local allocation - if (UseTLAB) { - builder()->SetInsertPoint(tlab_alloc); - - Value *top_addr = builder()->CreateAddressOfStructEntry( - thread(), Thread::tlab_top_offset(), - PointerType::getUnqual(SharkType::intptr_type()), - "top_addr"); - - Value *end = builder()->CreateValueOfStructEntry( - thread(), Thread::tlab_end_offset(), - SharkType::intptr_type(), - "end"); - - Value *old_top = builder()->CreateLoad(top_addr, "old_top"); - Value *new_top = builder()->CreateAdd( - old_top, LLVMValue::intptr_constant(size_in_bytes)); - - builder()->CreateCondBr( - builder()->CreateICmpULE(new_top, end), - got_tlab, heap_alloc); - - builder()->SetInsertPoint(got_tlab); - tlab_object = builder()->CreateIntToPtr( - old_top, SharkType::jobject_type(), "tlab_object"); - - builder()->CreateStore(new_top, top_addr); - builder()->CreateBr(initialize); - } - - // Heap allocation - builder()->SetInsertPoint(heap_alloc); - - Value *top_addr = builder()->CreateIntToPtr( - builder()->pointer_constant(Universe::heap()->top_addr()), - PointerType::getUnqual(SharkType::intptr_type()), - "top_addr"); - - Value *end = builder()->CreateLoad( - builder()->CreateIntToPtr( - builder()->pointer_constant(Universe::heap()->end_addr()), - PointerType::getUnqual(SharkType::intptr_type())), - "end"); - - builder()->CreateBr(retry); - builder()->SetInsertPoint(retry); - - Value *old_top = builder()->CreateLoad(top_addr, "top"); - Value *new_top = builder()->CreateAdd( - old_top, LLVMValue::intptr_constant(size_in_bytes)); - - builder()->CreateCondBr( - builder()->CreateICmpULE(new_top, end), - got_heap, slow_alloc_and_init); - - builder()->SetInsertPoint(got_heap); - heap_object = builder()->CreateIntToPtr( - old_top, SharkType::jobject_type(), "heap_object"); - - Value *check = builder()->CreateCmpxchgPtr(new_top, top_addr, old_top); - builder()->CreateCondBr( - builder()->CreateICmpEQ(old_top, check), - initialize, retry); - - // Initialize the object - builder()->SetInsertPoint(initialize); - if (tlab_object) { - PHINode *phi = builder()->CreatePHI( - SharkType::jobject_type(), "fast_object"); - phi->addIncoming(tlab_object, got_tlab); - phi->addIncoming(heap_object, got_heap); - fast_object = phi; - } - else { - fast_object = heap_object; - } - - builder()->CreateMemset( - builder()->CreateBitCast( - fast_object, PointerType::getUnqual(SharkType::jbyte_type())), - LLVMValue::jbyte_constant(0), - LLVMValue::jint_constant(size_in_bytes), - LLVMValue::jint_constant(HeapWordSize)); - - Value *mark_addr = builder()->CreateAddressOfStructEntry( - fast_object, in_ByteSize(oopDesc::mark_offset_in_bytes()), - PointerType::getUnqual(SharkType::intptr_type()), - "mark_addr"); - - Value *klass_addr = builder()->CreateAddressOfStructEntry( - fast_object, in_ByteSize(oopDesc::klass_offset_in_bytes()), - PointerType::getUnqual(SharkType::jobject_type()), - "klass_addr"); - - // Set the mark - intptr_t mark; - if (UseBiasedLocking) { - Unimplemented(); - } - else { - mark = (intptr_t) markOopDesc::prototype(); - } - builder()->CreateStore(LLVMValue::intptr_constant(mark), mark_addr); - - // Set the class - Value *rtklass = constants.object_at(iter()->get_klass_index()); - builder()->CreateStore(rtklass, klass_addr); - got_fast = builder()->GetInsertBlock(); - - builder()->CreateBr(push_object); - builder()->SetInsertPoint(slow_alloc_and_init); - fast_state = current_state()->copy(); - } - - // The slow path - call_vm( - SharkRuntime::new_instance(), - LLVMValue::jint_constant(iter()->get_klass_index())); - slow_object = function()->CreateGetVMResult(); - got_slow = builder()->GetInsertBlock(); - - // Push the object - if (push_object) { - builder()->CreateBr(push_object); - builder()->SetInsertPoint(push_object); - } - if (fast_object) { - PHINode *phi = builder()->CreatePHI(SharkType::jobject_type(), "object"); - phi->addIncoming(fast_object, got_fast); - phi->addIncoming(slow_object, got_slow); - object = phi; - current_state()->merge(fast_state, got_fast, got_slow); - } - else { - object = slow_object; - } - - SharkValue *result = SharkValue::create_jobject(object); - result->set_zero_checked(true); - push(result); + ShouldNotCallThis(); } void SharkBlock::do_newarray() { - BasicType type = (BasicType) iter()->get_index(); - - call_vm( - SharkRuntime::newarray(), - LLVMValue::jint_constant(type), - pop()->jint_value()); - - SharkValue *result = SharkValue::create_generic( - ciArrayKlass::make(ciType::make(type)), - function()->CreateGetVMResult()); - result->set_zero_checked(true); - push(result); + ShouldNotCallThis(); } void SharkBlock::do_anewarray() { - bool will_link; - ciKlass *klass = iter()->get_klass(will_link); - assert(will_link, "typeflow responsibility"); - - ciObjArrayKlass *array_klass = ciObjArrayKlass::make(klass); - if (!array_klass->is_loaded()) { - Unimplemented(); - } - - call_vm( - SharkRuntime::anewarray(), - LLVMValue::jint_constant(iter()->get_klass_index()), - pop()->jint_value()); - - SharkValue *result = SharkValue::create_generic( - array_klass, function()->CreateGetVMResult()); - result->set_zero_checked(true); - push(result); + ShouldNotCallThis(); } void SharkBlock::do_multianewarray() { - bool will_link; - ciArrayKlass *array_klass = iter()->get_klass(will_link)->as_array_klass(); - assert(will_link, "typeflow responsibility"); - - // The dimensions are stack values, so we use their slots for the - // dimensions array. Note that we are storing them in the reverse - // of normal stack order. - int ndims = iter()->get_dimensions(); - - Value *dimensions = function()->CreateAddressOfFrameEntry( - function()->stack_slots_offset() + max_stack() - xstack_depth(), - ArrayType::get(SharkType::jint_type(), ndims), - "dimensions"); - - for (int i = 0; i < ndims; i++) { - builder()->CreateStore( - xstack(ndims - 1 - i)->jint_value(), - builder()->CreateStructGEP(dimensions, i)); - } - - call_vm( - SharkRuntime::multianewarray(), - LLVMValue::jint_constant(iter()->get_klass_index()), - LLVMValue::jint_constant(ndims), - builder()->CreateStructGEP(dimensions, 0)); - - // Now we can pop the dimensions off the stack - for (int i = 0; i < ndims; i++) - pop(); - - SharkValue *result = SharkValue::create_generic( - array_klass, function()->CreateGetVMResult()); - result->set_zero_checked(true); - push(result); + ShouldNotCallThis(); } void SharkBlock::do_monitorenter() { - SharkValue *lockee = pop(); - check_null(lockee); - Value *object = lockee->jobject_value(); - - // Find a free monitor, or one already allocated for this object - BasicBlock *loop_top = function()->CreateBlock("loop_top"); - BasicBlock *loop_iter = function()->CreateBlock("loop_iter"); - BasicBlock *loop_check = function()->CreateBlock("loop_check"); - BasicBlock *no_monitor = function()->CreateBlock("no_monitor"); - BasicBlock *got_monitor = function()->CreateBlock("got_monitor"); - - BasicBlock *entry_block = builder()->GetInsertBlock(); - builder()->CreateBr(loop_check); - - builder()->SetInsertPoint(loop_check); - PHINode *index = builder()->CreatePHI(SharkType::jint_type(), "index"); - index->addIncoming( - LLVMValue::jint_constant(function()->monitor_count() - 1), entry_block); - builder()->CreateCondBr( - builder()->CreateICmpUGE(index, LLVMValue::jint_constant(0)), - loop_top, no_monitor); - - builder()->SetInsertPoint(loop_top); - SharkMonitor* monitor = function()->monitor(index); - Value *smo = monitor->object(); - builder()->CreateCondBr( - builder()->CreateOr( - builder()->CreateICmpEQ(smo, LLVMValue::null()), - builder()->CreateICmpEQ(smo, object)), - got_monitor, loop_iter); - - builder()->SetInsertPoint(loop_iter); - index->addIncoming( - builder()->CreateSub(index, LLVMValue::jint_constant(1)), loop_iter); - builder()->CreateBr(loop_check); - - builder()->SetInsertPoint(no_monitor); - builder()->CreateShouldNotReachHere(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - // Acquire the lock - builder()->SetInsertPoint(got_monitor); - monitor->acquire(this, object); - check_pending_exception(); + ShouldNotCallThis(); } void SharkBlock::do_monitorexit() { - SharkValue *lockee = pop(); - // The monitorexit can't throw an NPE because the verifier checks - // that the monitor operations are block structured before we - // compile. - // check_null(lockee); - Value *object = lockee->jobject_value(); - - // Find the monitor associated with this object - BasicBlock *loop_top = function()->CreateBlock("loop_top"); - BasicBlock *loop_iter = function()->CreateBlock("loop_iter"); - BasicBlock *loop_check = function()->CreateBlock("loop_check"); - BasicBlock *no_monitor = function()->CreateBlock("no_monitor"); - BasicBlock *got_monitor = function()->CreateBlock("got_monitor"); - - BasicBlock *entry_block = builder()->GetInsertBlock(); - builder()->CreateBr(loop_check); - - builder()->SetInsertPoint(loop_check); - PHINode *index = builder()->CreatePHI(SharkType::jint_type(), "index"); - index->addIncoming( - LLVMValue::jint_constant(function()->monitor_count() - 1), entry_block); - builder()->CreateCondBr( - builder()->CreateICmpUGE(index, LLVMValue::jint_constant(0)), - loop_top, no_monitor); - - builder()->SetInsertPoint(loop_top); - SharkMonitor* monitor = function()->monitor(index); - Value *smo = monitor->object(); - builder()->CreateCondBr( - builder()->CreateICmpEQ(smo, object), - got_monitor, loop_iter); - - builder()->SetInsertPoint(loop_iter); - index->addIncoming( - builder()->CreateSub(index, LLVMValue::jint_constant(1)), loop_iter); - builder()->CreateBr(loop_check); - - builder()->SetInsertPoint(no_monitor); - builder()->CreateShouldNotReachHere(__FILE__, __LINE__); - builder()->CreateUnreachable(); - - // Release the lock - builder()->SetInsertPoint(got_monitor); - monitor->release(this); - // The monitorexit can't throw an NPE because the verifier checks - // that the monitor operations are block structured before we - // compile. - // check_pending_exception(); + ShouldNotCallThis(); } diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkBlock.hpp --- a/ports/hotspot/src/share/vm/shark/sharkBlock.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkBlock.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -23,119 +23,46 @@ * */ +class SharkState; + class SharkBlock : public ResourceObj { public: - SharkBlock(SharkFunction* function, ciTypeFlow::Block* ciblock) - : _function(function), - _ciblock(ciblock), - _entered(false), - _needs_phis(false), - _entry_state(NULL), - _entry_block(NULL), - _current_state(NULL) {} + SharkBlock(SharkBuilder* builder, ciMethod* target, ciBytecodeStream* iter) + : _builder(builder),_target(target),_iter(iter),_current_state(NULL) {} private: - SharkFunction* _function; - ciTypeFlow::Block* _ciblock; - - public: - SharkFunction* function() const - { - return _function; - } - ciTypeFlow::Block* ciblock() const - { - return _ciblock; - } + SharkBuilder* _builder; + ciMethod* _target; + ciBytecodeStream* _iter; + SharkState* _current_state; public: SharkBuilder* builder() const { - return function()->builder(); + return _builder; } ciMethod* target() const { - return function()->target(); + return _target; } - llvm::Value* thread() const + ciBytecodeStream* iter() const { - return function()->thread(); + return _iter; } - // Typeflow properties + // Target properties public: - int index() const - { - return ciblock()->pre_order(); - } - bool has_trap() const - { - return ciblock()->has_trap(); - } - int trap_index() const - { - return ciblock()->trap_index(); - } - bool is_private_copy() const - { - return ciblock()->is_backedge_copy(); - } int max_locals() const { - return ciblock()->outer()->max_locals(); + return target()->max_locals(); } int max_stack() const { - return ciblock()->outer()->max_stack(); - } - int stack_depth_at_entry() const - { - return ciblock()->stack_size(); - } - ciType* local_type_at_entry(int index) const - { - return ciblock()->local_type_at(index); - } - ciType* stack_type_at_entry(int slot) const - { - return ciblock()->stack_type_at(slot); + return target()->max_stack(); } - int start() const - { - return ciblock()->start(); - } - int limit() const - { - return ciblock()->limit(); - } - bool falls_through() const - { - return ciblock()->control() == ciBlock::fall_through_bci; - } - int num_exceptions() const - { - return ciblock()->exceptions()->length(); - } - SharkBlock* exception(int index) const - { - return function()->block(ciblock()->exceptions()->at(index)->pre_order()); - } - int num_successors() const - { - return ciblock()->successors()->length(); - } - SharkBlock* successor(int index) const - { - return function()->block(ciblock()->successors()->at(index)->pre_order()); - } - SharkBlock* bci_successor(int bci) const; - + // Bytecode stream public: - ciBytecodeStream* iter() const - { - return function()->iter(); - } Bytecodes::Code bc() const { return iter()->cur_bc(); @@ -146,93 +73,29 @@ } // Entry state + protected: + virtual SharkState* entry_state(); + + // Current state private: - bool _entered; - bool _needs_phis; - + SharkState* initial_current_state(); + public: - bool entered() const - { - return _entered; - } - bool needs_phis() const + SharkState* current_state() { - return _needs_phis; - } - - private: - void enter(SharkBlock* predecessor, bool is_exception); - - public: - void enter() - { - enter(NULL, false); + if (_current_state == NULL) + set_current_state(initial_current_state()); + return _current_state; } - private: - SharkState* _entry_state; - - private: - SharkState* entry_state() - { - if (_entry_state == NULL) { - assert(needs_phis(), "should do"); - _entry_state = new SharkPHIState(this); - } - return _entry_state; - } - - private: - llvm::BasicBlock* _entry_block; - - public: - llvm::BasicBlock* entry_block() const - { - return _entry_block; - } - - public: - void initialize(); - - public: - void add_incoming(SharkState* incoming_state) - { - if (needs_phis()) { - ((SharkPHIState *) entry_state())->add_incoming(incoming_state); - } - else if (_entry_state != incoming_state) { - assert(_entry_state == NULL, "should be"); - _entry_state = incoming_state; - } - } - - // Current state - private: - SharkTrackingState* _current_state; - - private: - void set_current_state(SharkTrackingState* current_state) + protected: + void set_current_state(SharkState* current_state) { _current_state = current_state; } - public: - SharkTrackingState* current_state() - { - if (_current_state == NULL) - set_current_state(new SharkTrackingState(entry_state())); - return _current_state; - } - - // Method - public: - llvm::Value* method() - { - return current_state()->method(); - } - // Local variables - private: + protected: SharkValue* local(int index) { SharkValue *value = current_state()->local(index); @@ -251,7 +114,7 @@ } // Expression stack (raw) - private: + protected: void xpush(SharkValue* value) { current_state()->push(value); @@ -275,7 +138,7 @@ } // Expression stack (cooked) - private: + protected: void push(SharkValue* value) { assert(value != NULL, "shouldn't be"); @@ -292,133 +155,90 @@ assert(value && value->size() == size, "should be"); return value; } - - // VM calls - private: - llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, - llvm::Value** args_start, - llvm::Value** args_end) + SharkValue* pop_result(BasicType type) { - current_state()->decache_for_VM_call(); - function()->set_last_Java_frame(); - llvm::CallInst *res = builder()->CreateCall(callee, args_start, args_end); - function()->reset_last_Java_frame(); - current_state()->cache_after_VM_call(); - return res; - } + SharkValue *result = pop(); + +#ifdef ASSERT + switch (result->basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + assert(type == T_INT, "type mismatch"); + break; - llvm::CallInst* call_vm(llvm::Constant* callee, - llvm::Value** args_start, - llvm::Value** args_end) - { - llvm::CallInst* res = call_vm_nocheck(callee, args_start, args_end); - check_pending_exception(); - return res; + case T_ARRAY: + assert(type == T_OBJECT, "type mismatch"); + break; + + default: + assert(result->basic_type() == type, "type mismatch"); + } +#endif // ASSERT + + return result; } + // Code generation public: - llvm::CallInst* call_vm(llvm::Constant* callee) - { - llvm::Value *args[] = {thread()}; - return call_vm(callee, args, args + 1); - } - llvm::CallInst* call_vm(llvm::Constant* callee, - llvm::Value* arg1) - { - llvm::Value *args[] = {thread(), arg1}; - return call_vm(callee, args, args + 2); - } - llvm::CallInst* call_vm(llvm::Constant* callee, - llvm::Value* arg1, - llvm::Value* arg2) - { - llvm::Value *args[] = {thread(), arg1, arg2}; - return call_vm(callee, args, args + 3); - } - llvm::CallInst* call_vm(llvm::Constant* callee, - llvm::Value* arg1, - llvm::Value* arg2, - llvm::Value* arg3) - { - llvm::Value *args[] = {thread(), arg1, arg2, arg3}; - return call_vm(callee, args, args + 4); - } + virtual void emit_IR(); + + protected: + void parse_bytecode(int start, int limit); - llvm::CallInst* call_vm_nocheck(llvm::Constant* callee) - { - llvm::Value *args[] = {thread()}; - return call_vm_nocheck(callee, args, args + 1); - } - llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, - llvm::Value* arg1) - { - llvm::Value *args[] = {thread(), arg1}; - return call_vm_nocheck(callee, args, args + 2); - } - llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, - llvm::Value* arg1, - llvm::Value* arg2) - { - llvm::Value *args[] = {thread(), arg1, arg2}; - return call_vm_nocheck(callee, args, args + 3); - } - llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, - llvm::Value* arg1, - llvm::Value* arg2, - llvm::Value* arg3) - { - llvm::Value *args[] = {thread(), arg1, arg2, arg3}; - return call_vm_nocheck(callee, args, args + 4); - } + // Helpers + protected: + virtual void do_zero_check(SharkValue* value); + virtual llvm::Value* lookup_for_ldc(); + virtual llvm::Value* lookup_for_field_access(); - llvm::CallInst* call_vm_leaf(llvm::Constant* callee, - llvm::Value* arg1) + // Leaf calls + protected: + llvm::CallInst* call_vm_leaf(llvm::Constant* callee, llvm::Value* arg1) { return builder()->CreateCall(callee, arg1); } - // Whole-method synchronization - public: - void acquire_method_lock(); - void release_method_lock(); - - // Error checking - private: + // Zero checking + protected: void check_null(SharkValue* object) { - check_zero(object); + zero_check(object); } void check_divide_by_zero(SharkValue* value) { - check_zero(value); + zero_check(value); } - void check_zero(SharkValue* value); - void check_bounds(SharkValue* array, SharkValue* index); - void check_pending_exception(bool attempt_catch = true); - void handle_exception(llvm::Value* exception, bool attempt_catch = true); + private: + void zero_check(SharkValue* value) + { + if (!value->zero_checked()) + do_zero_check(value); + } // Safepoints - private: - void add_safepoint(); - - // Returns - private: - void call_register_finalizer(llvm::Value* receiver); - void handle_return(BasicType type, llvm::Value* exception); - void release_locked_monitors(); + protected: + virtual void add_safepoint(); // ldc* private: - void do_ldc(); + void do_ldc() + { + SharkValue *value = SharkValue::from_ciConstant(iter()->get_constant()); + if (value == NULL) + value = SharkValue::create_jobject(lookup_for_ldc()); + push(value); + } // arraylength - private: - void do_arraylength(); + protected: + virtual void do_arraylength(); // *aload and *astore - private: - void do_aload(BasicType basic_type); - void do_astore(BasicType basic_type); + protected: + virtual void do_aload(BasicType basic_type); + virtual void do_astore(BasicType basic_type); // *div and *rem private: @@ -438,8 +258,8 @@ { do_div_or_rem(true, true); } - void do_div_or_rem(bool is_long, bool is_rem); - + void do_div_or_rem(bool is_long, bool is_rem); + // get* and put* private: void do_getstatic() @@ -458,7 +278,7 @@ { do_field_access(false, true); } - void do_field_access(bool is_get, bool is_field, ciField* field = NULL); + void do_field_access(bool is_get, bool is_field); // lcmp and [fd]cmp[lg] private: @@ -466,75 +286,49 @@ void do_fcmp(bool is_double, bool unordered_is_greater); // *return and athrow - private: - void do_return(BasicType type) - { - if (target()->intrinsic_id() == vmIntrinsics::_Object_init) - call_register_finalizer(local(0)->jobject_value()); - else - add_safepoint(); - handle_return(type, NULL); - } - void do_athrow() - { - SharkValue *exception = pop(); - check_null(exception); - handle_exception(exception->jobject_value()); - } + protected: + virtual void do_return(BasicType type); + virtual void do_athrow(); + + // goto* + protected: + virtual void do_goto(); + + // jsr* and ret + protected: + virtual void do_jsr(); + virtual void do_ret(); // if* - private: - void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); + protected: + virtual void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); - // tableswitch and lookupswitch - private: + // *switch + protected: int switch_default_dest(); int switch_table_length(); int switch_key(int i); int switch_dest(int i); - void do_switch(); - + virtual void do_switch(); + // invoke* - private: - enum CallType { - CALL_DIRECT, - CALL_VIRTUAL, - CALL_INTERFACE - }; - CallType get_call_type(ciMethod* method); - llvm::Value* get_callee(CallType call_type, - ciMethod* method, - SharkValue* receiver); - - llvm::Value* get_direct_callee(ciMethod* method); - llvm::Value* get_virtual_callee(SharkValue* receiver, ciMethod* method); - - llvm::Value* get_virtual_callee(llvm::Value* cache, SharkValue* receiver); - llvm::Value* get_interface_callee(SharkValue* receiver); - - bool maybe_inline_call(ciMethod* method); - bool maybe_inline_accessor(ciMethod* method, bool is_field); - - void do_call(); + protected: + virtual void do_call(); // checkcast and instanceof - private: - void do_instance_check(); + protected: + virtual void do_instance_check(); // new and *newarray - private: - void do_new(); - void do_newarray(); - void do_anewarray(); - void do_multianewarray(); + protected: + virtual void do_new(); + virtual void do_newarray(); + virtual void do_anewarray(); + virtual void do_multianewarray(); // monitorenter and monitorexit - private: - void do_monitorenter(); - void do_monitorexit(); - - // The big one - public: - void parse(); + protected: + virtual void do_monitorenter(); + virtual void do_monitorexit(); }; diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkBuilder.hpp --- a/ports/hotspot/src/share/vm/shark/sharkBuilder.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkBuilder.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -111,6 +111,35 @@ public: llvm::Function *CreateFunction(const char *name = "func"); + // Helpers for creating basic blocks + // NB don't use unless SharkFunction::CreateBlock is unavailable + public: + llvm::BasicBlock* GetBlockInsertionPoint() const + { + llvm::BasicBlock *cur = GetInsertBlock(); + + // BasicBlock::Create takes an insertBefore argument, so + // we need to find the block _after_ the current block + llvm::Function::iterator iter = cur->getParent()->begin(); + llvm::Function::iterator end = cur->getParent()->end(); + while (iter != end) { + iter++; + if (&*iter == cur) { + iter++; + break; + } + } + + if (iter == end) + return NULL; + else + return iter; + } + llvm::BasicBlock* CreateBlock(llvm::BasicBlock* ip, const char* name="") const + { + return llvm::BasicBlock::Create(name, GetInsertBlock()->getParent(), ip); + } + // Helpers for accessing structures and arrays public: llvm::Value* CreateAddressOfStructEntry(llvm::Value* base, diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp --- a/ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkConstantPool.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -25,17 +25,17 @@ class SharkConstantPool : public StackObj { public: - SharkConstantPool(SharkBlock* block) + SharkConstantPool(SharkTopLevelBlock* block) : _block(block), _constants_method(NULL), _tags_constants(NULL), _cache_constants(NULL) {} private: - SharkBlock* _block; + SharkTopLevelBlock* _block; private: - SharkBlock* block() const + SharkTopLevelBlock* block() const { return _block; } diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkFunction.cpp --- a/ports/hotspot/src/share/vm/shark/sharkFunction.cpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkFunction.cpp Wed Mar 04 10:41:13 2009 -0500 @@ -30,6 +30,65 @@ using namespace llvm; +class SharkEntryState : public SharkState { + public: + SharkEntryState(SharkTopLevelBlock* block, llvm::Value* method) + : SharkState(block, block->function(), method) + { + char name[18]; + + // Local variables + for (int i = 0; i < max_locals(); i++) { + ciType *type = block->local_type_at_entry(i); + + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + if (i < function()->arg_size()) { + snprintf(name, sizeof(name), "local_%d_", i); + value = SharkValue::create_generic( + type, + builder()->CreateLoad( + function()->CreateAddressOfFrameEntry( + function()->locals_slots_offset() + + max_locals() - type->size() - i, + SharkType::to_stackType(type)), + name)); + } + else { + Unimplemented(); + } + break; + + case ciTypeFlow::StateVector::T_BOTTOM: + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); + } + set_local(i, value); + } + + // Non-static methods have a guaranteed non-null receiver + if (!function()->target()->is_static()) { + assert(local(0)->is_jobject(), "should be"); + local(0)->set_zero_checked(true); + } + + // Expression stack + assert(!block->stack_depth_at_entry(), "entry block shouldn't have stack"); + } +}; + void SharkFunction::initialize() { // Emit the entry point @@ -47,19 +106,19 @@ // Create the list of blocks set_block_insertion_point(NULL); - _blocks = NEW_RESOURCE_ARRAY(SharkBlock*, flow()->block_count()); + _blocks = NEW_RESOURCE_ARRAY(SharkTopLevelBlock*, flow()->block_count()); for (int i = 0; i < block_count(); i++) { ciTypeFlow::Block *b = flow()->pre_order_at(i); // Work around a bug in pre_order_at() that does not return the // correct pre-ordering. If pre_order_at() were correct this // line could simply be: - // _blocks[i] = new SharkBlock(this, b); - _blocks[b->pre_order()] = new SharkBlock(this, b); + // _blocks[i] = new SharkTopLevelBlock(this, b); + _blocks[b->pre_order()] = new SharkTopLevelBlock(this, b); } // Walk the tree from the start block to determine which // blocks are entered and which blocks require phis - SharkBlock *start_block = block(0); + SharkTopLevelBlock *start_block = block(0); assert(start_block->start() == 0, "blocks out of order"); start_block->enter(); @@ -99,9 +158,10 @@ "method_slot"))); // Lock if necessary - SharkState *entry_state = new SharkEntryState(method, start_block); + SharkState *entry_state = new SharkEntryState(start_block, method); if (target()->is_synchronized()) { - SharkBlock *locker = new SharkBlock(this, start_block->ciblock()); + SharkTopLevelBlock *locker = + new SharkTopLevelBlock(this, start_block->ciblock()); locker->add_incoming(entry_state); set_block_insertion_point(start_block->entry_block()); @@ -124,7 +184,7 @@ else set_block_insertion_point(NULL); - block(i)->parse(); + block(i)->emit_IR(); } // Dump the bitcode, if requested diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkFunction.hpp --- a/ports/hotspot/src/share/vm/shark/sharkFunction.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkFunction.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -23,7 +23,7 @@ * */ -class SharkBlock; +class SharkTopLevelBlock; class SharkMonitor; class SharkFunction : public StackObj { @@ -44,16 +44,16 @@ void initialize(); private: - SharkBuilder* _builder; - const char* _name; - ciTypeFlow* _flow; - ciBytecodeStream* _iter; - MacroAssembler* _masm; - llvm::Function* _function; - SharkBlock** _blocks; - llvm::Value* _base_pc; - llvm::Value* _thread; - int _monitor_count; + SharkBuilder* _builder; + const char* _name; + ciTypeFlow* _flow; + ciBytecodeStream* _iter; + MacroAssembler* _masm; + llvm::Function* _function; + SharkTopLevelBlock** _blocks; + llvm::Value* _base_pc; + llvm::Value* _thread; + int _monitor_count; public: SharkBuilder* builder() const @@ -80,7 +80,7 @@ { return _function; } - SharkBlock* block(int i) const + SharkTopLevelBlock* block(int i) const { return _blocks[i]; } diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkInliner.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkInliner.cpp Wed Mar 04 10:41:13 2009 -0500 @@ -0,0 +1,761 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkInliner.cpp.incl" + +using namespace llvm; + +class SharkInlineBlock : public SharkBlock { + public: + SharkInlineBlock(ciMethod* target, + SharkState* state, + ciBytecodeStream* iter) + : SharkBlock(state->builder(), target, iter), + _outer_state(state), + _entry_state(new SharkState(this)) + { + for (int i = target->max_locals() - 1; i >= 0; i--) { + SharkValue *value = NULL; + if (i < target->arg_size()) + value = outer_state()->pop(); + entry_state()->set_local(i, value); + } + } + + private: + SharkState* _outer_state; + SharkState* _entry_state; + + private: + SharkState* outer_state() + { + return _outer_state; + } + SharkState* entry_state() + { + return _entry_state; + } + + public: + void emit_IR() + { + parse_bytecode(0, target()->code_size()); + } + + private: + void do_return(BasicType type) + { + if (type != T_VOID) { + SharkValue *result = pop_result(type); + outer_state()->push(result); + if (result->is_two_word()) + outer_state()->push(NULL); + } + } +}; + +class SharkInlinerHelper : public StackObj { + public: + SharkInlinerHelper(ciMethod* target, SharkState* entry_state) + : _target(target), _entry_state(entry_state), _iter(target) {} + + private: + ciBytecodeStream _iter; + SharkState* _entry_state; + ciMethod* _target; + + public: + ciBytecodeStream* iter() + { + return &_iter; + } + SharkState* entry_state() const + { + return _entry_state; + } + ciMethod* target() const + { + return _target; + } + + public: + Bytecodes::Code bc() + { + return iter()->cur_bc(); + } + int max_locals() const + { + return target()->max_locals(); + } + int max_stack() const + { + return target()->max_stack(); + } + + // Inlinability check + public: + bool is_inlinable(); + + private: + void initialize_for_check(); + + bool do_getstatic() + { + return do_field_access(true, false); + } + bool do_getfield() + { + return do_field_access(true, true); + } + bool do_putfield() + { + return do_field_access(false, true); + } + bool do_field_access(bool is_get, bool is_field); + + // Local variables for inlinability check + private: + bool* _locals; + + public: + bool* local_addr(int index) const + { + assert(index >= 0 && index < max_locals(), "bad local variable index"); + return &_locals[index]; + } + bool local(int index) const + { + return *local_addr(index); + } + void set_local(int index, bool value) + { + *local_addr(index) = value; + } + + // Expression stack for inlinability check + private: + bool* _stack; + bool* _sp; + + public: + int stack_depth() const + { + return _sp - _stack; + } + bool* stack_addr(int slot) const + { + assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); + return &_sp[-(slot + 1)]; + } + void push(bool value) + { + assert(stack_depth() < max_stack(), "stack overrun"); + *(_sp++) = value; + } + bool pop() + { + assert(stack_depth() > 0, "stack underrun"); + return *(--_sp); + } + + // Methods for two-word locals + public: + void push_pair_local(int index) + { + push(local(index)); + push(local(index + 1)); + } + void pop_pair_local(int index) + { + set_local(index + 1, pop()); + set_local(index, pop()); + } + + // Code generation + public: + void do_inline() + { + (new SharkInlineBlock(target(), entry_state(), iter()))->emit_IR(); + } +}; + +// Quick checks so we can bail out before doing too much +bool SharkInliner::may_be_inlinable(ciMethod *target) +{ + // We can't inline native methods + if (target->is_native()) + return false; + + // Not much point inlining abstract ones, and in any + // case we'd need a stack frame to throw the exception + if (target->is_abstract()) + return false; + + // Don't inline anything huge + if (target->code_size() > SharkMaxInlineSize) + return false; + + // Monitors aren't allowed without a frame to put them in + if (target->is_synchronized() || target->has_monitor_bytecodes()) + return false; + + // We don't do control flow + if (target->has_exception_handlers() || target->has_jsrs()) + return false; + + // Mustn't inline Object. + if (target->intrinsic_id() == vmIntrinsics::_Object_init) + return false; + + return true; +} + +// Full-on detailed check, for methods that pass the quick checks +// Inlined methods have no stack frame, so we can't do anything +// that would require one. This means no safepoints (and hence +// no loops) and no VM calls. No VM calls means, amongst other +// things, that no exceptions can be created, which means no null +// checks or divide-by-zero checks are allowed. The lack of null +// checks in particular would eliminate practically everything, +// but we can get around that restriction by relying on the zero- +// check eliminator to strip the checks. To do that, we need to +// walk through the method, tracking which values are and are not +// zero-checked. +bool SharkInlinerHelper::is_inlinable() +{ + ResourceMark rm; + initialize_for_check(); + + SharkValue *sv; + bool a, b, c, d; + + iter()->reset_to_bci(0); + while (iter()->next() != ciBytecodeStream::EOBC()) { + switch (bc()) { + case Bytecodes::_nop: + break; + + case Bytecodes::_aconst_null: + push(false); + break; + + case Bytecodes::_iconst_0: + push(false); + break; + case Bytecodes::_iconst_m1: + case Bytecodes::_iconst_1: + case Bytecodes::_iconst_2: + case Bytecodes::_iconst_3: + case Bytecodes::_iconst_4: + case Bytecodes::_iconst_5: + push(true); + break; + + case Bytecodes::_lconst_0: + push(false); + push(false); + break; + case Bytecodes::_lconst_1: + push(true); + push(false); + break; + + case Bytecodes::_fconst_0: + case Bytecodes::_fconst_1: + case Bytecodes::_fconst_2: + push(false); + break; + + case Bytecodes::_dconst_0: + case Bytecodes::_dconst_1: + push(false); + push(false); + break; + + case Bytecodes::_bipush: + push(iter()->get_byte() != 0); + break; + case Bytecodes::_sipush: + push(iter()->get_short() != 0); + break; + + case Bytecodes::_ldc: + case Bytecodes::_ldc_w: + case Bytecodes::_ldc2_w: + sv = SharkValue::from_ciConstant(iter()->get_constant()); + if (sv == NULL) + return false; + push(sv->zero_checked()); + if (sv->is_two_word()) + push(false); + break; + + case Bytecodes::_iload_0: + case Bytecodes::_fload_0: + case Bytecodes::_aload_0: + push(local(0)); + break; + case Bytecodes::_lload_0: + case Bytecodes::_dload_0: + push_pair_local(0); + break; + + case Bytecodes::_iload_1: + case Bytecodes::_fload_1: + case Bytecodes::_aload_1: + push(local(1)); + break; + case Bytecodes::_lload_1: + case Bytecodes::_dload_1: + push_pair_local(1); + break; + + case Bytecodes::_iload_2: + case Bytecodes::_fload_2: + case Bytecodes::_aload_2: + push(local(2)); + break; + case Bytecodes::_lload_2: + case Bytecodes::_dload_2: + push_pair_local(2); + break; + + case Bytecodes::_iload_3: + case Bytecodes::_fload_3: + case Bytecodes::_aload_3: + push(local(3)); + break; + case Bytecodes::_lload_3: + case Bytecodes::_dload_3: + push_pair_local(3); + break; + + case Bytecodes::_iload: + case Bytecodes::_fload: + case Bytecodes::_aload: + push(local(iter()->get_index())); + break; + case Bytecodes::_lload: + case Bytecodes::_dload: + push_pair_local(iter()->get_index()); + break; + + case Bytecodes::_istore_0: + case Bytecodes::_fstore_0: + case Bytecodes::_astore_0: + set_local(0, pop()); + break; + case Bytecodes::_lstore_0: + case Bytecodes::_dstore_0: + pop_pair_local(0); + break; + + case Bytecodes::_istore_1: + case Bytecodes::_fstore_1: + case Bytecodes::_astore_1: + set_local(1, pop()); + break; + case Bytecodes::_lstore_1: + case Bytecodes::_dstore_1: + pop_pair_local(1); + break; + + case Bytecodes::_istore_2: + case Bytecodes::_fstore_2: + case Bytecodes::_astore_2: + set_local(2, pop()); + break; + case Bytecodes::_lstore_2: + case Bytecodes::_dstore_2: + pop_pair_local(2); + break; + + case Bytecodes::_istore_3: + case Bytecodes::_fstore_3: + case Bytecodes::_astore_3: + set_local(3, pop()); + break; + case Bytecodes::_lstore_3: + case Bytecodes::_dstore_3: + pop_pair_local(3); + break; + + case Bytecodes::_istore: + case Bytecodes::_fstore: + case Bytecodes::_astore: + set_local(iter()->get_index(), pop()); + break; + case Bytecodes::_lstore: + case Bytecodes::_dstore: + pop_pair_local(iter()->get_index()); + break; + + case Bytecodes::_pop: + pop(); + break; + case Bytecodes::_pop2: + pop(); + pop(); + break; + case Bytecodes::_swap: + a = pop(); + b = pop(); + push(a); + push(b); + break; + case Bytecodes::_dup: + a = pop(); + push(a); + push(a); + break; + case Bytecodes::_dup_x1: + a = pop(); + b = pop(); + push(a); + push(b); + push(a); + break; + case Bytecodes::_dup_x2: + a = pop(); + b = pop(); + c = pop(); + push(a); + push(c); + push(b); + push(a); + break; + case Bytecodes::_dup2: + a = pop(); + b = pop(); + push(b); + push(a); + push(b); + push(a); + break; + case Bytecodes::_dup2_x1: + a = pop(); + b = pop(); + c = pop(); + push(b); + push(a); + push(c); + push(b); + push(a); + break; + case Bytecodes::_dup2_x2: + a = pop(); + b = pop(); + c = pop(); + d = pop(); + push(b); + push(a); + push(d); + push(c); + push(b); + push(a); + break; + + case Bytecodes::_getfield: + if (!do_getfield()) + return false; + break; + case Bytecodes::_getstatic: + if (!do_getstatic()) + return false; + break; + case Bytecodes::_putfield: + if (!do_putfield()) + return false; + break; + + case Bytecodes::_iadd: + case Bytecodes::_isub: + case Bytecodes::_imul: + case Bytecodes::_iand: + case Bytecodes::_ior: + case Bytecodes::_ixor: + case Bytecodes::_ishl: + case Bytecodes::_ishr: + case Bytecodes::_iushr: + pop(); + pop(); + push(false); + break; + case Bytecodes::_idiv: + case Bytecodes::_irem: + if (!pop()) + return false; + pop(); + push(false); + break; + case Bytecodes::_ineg: + break; + + case Bytecodes::_ladd: + case Bytecodes::_lsub: + case Bytecodes::_lmul: + case Bytecodes::_land: + case Bytecodes::_lor: + case Bytecodes::_lxor: + pop(); + pop(); + pop(); + pop(); + push(false); + push(false); + break; + case Bytecodes::_ldiv: + case Bytecodes::_lrem: + pop(); + if (!pop()) + return false; + pop(); + pop(); + push(false); + push(false); + break; + case Bytecodes::_lneg: + break; + case Bytecodes::_lshl: + case Bytecodes::_lshr: + case Bytecodes::_lushr: + pop(); + pop(); + pop(); + push(false); + push(false); + break; + + case Bytecodes::_fadd: + case Bytecodes::_fsub: + case Bytecodes::_fmul: + case Bytecodes::_fdiv: + case Bytecodes::_frem: + pop(); + pop(); + push(false); + break; + case Bytecodes::_fneg: + break; + + case Bytecodes::_dadd: + case Bytecodes::_dsub: + case Bytecodes::_dmul: + case Bytecodes::_ddiv: + case Bytecodes::_drem: + pop(); + pop(); + pop(); + pop(); + push(false); + push(false); + break; + case Bytecodes::_dneg: + break; + + case Bytecodes::_iinc: + set_local(iter()->get_index(), false); + break; + + case Bytecodes::_lcmp: + pop(); + pop(); + pop(); + pop(); + push(false); + break; + + case Bytecodes::_fcmpl: + case Bytecodes::_fcmpg: + pop(); + pop(); + push(false); + break; + + case Bytecodes::_dcmpl: + case Bytecodes::_dcmpg: + pop(); + pop(); + pop(); + pop(); + push(false); + break; + + case Bytecodes::_i2l: + push(false); + break; + case Bytecodes::_i2f: + pop(); + push(false); + break; + case Bytecodes::_i2d: + pop(); + push(false); + push(false); + break; + + case Bytecodes::_l2i: + case Bytecodes::_l2f: + pop(); + pop(); + push(false); + break; + case Bytecodes::_l2d: + pop(); + pop(); + push(false); + push(false); + break; + + case Bytecodes::_f2i: + pop(); + push(false); + break; + case Bytecodes::_f2l: + case Bytecodes::_f2d: + pop(); + push(false); + push(false); + break; + + case Bytecodes::_d2i: + case Bytecodes::_d2f: + pop(); + pop(); + push(false); + break; + case Bytecodes::_d2l: + pop(); + pop(); + push(false); + push(false); + break; + + case Bytecodes::_i2b: + case Bytecodes::_i2c: + case Bytecodes::_i2s: + pop(); + push(false); + break; + + case Bytecodes::_return: + case Bytecodes::_ireturn: + case Bytecodes::_lreturn: + case Bytecodes::_freturn: + case Bytecodes::_dreturn: + case Bytecodes::_areturn: + break; + + default: + return false; + } + } + + return true; +} + +void SharkInlinerHelper::initialize_for_check() +{ + _locals = NEW_RESOURCE_ARRAY(bool, max_locals()); + _stack = NEW_RESOURCE_ARRAY(bool, max_stack()); + + memset(_locals, 0, max_locals() * sizeof(bool)); + for (int i = 0; i < target()->arg_size(); i++) { + SharkValue *arg = entry_state()->stack(target()->arg_size() - 1 - i); + if (arg && arg->zero_checked()) + set_local(i, true); + } + + _sp = _stack; +} + +bool SharkInlinerHelper::do_field_access(bool is_get, bool is_field) +{ + assert(is_get || is_field, "can't inline putstatic"); + + // If the holder isn't linked then there isn't a lot we can do + if (!target()->holder()->is_linked()) + return false; + + // Get the field + bool will_link; + ciField *field = iter()->get_field(will_link); + if (!will_link) + return false; + + // If the field is mismatched then an exception needs throwing + if (is_field == field->is_static()) + return false; + + // Pop the value off the stack if necessary + if (!is_get) { + pop(); + if (field->type()->is_two_word()) + pop(); + } + + // Pop and null-check the receiver if necessary + if (is_field) { + if (!pop()) + return false; + } + + // Push the result if necessary + if (is_get) { + bool result_pushed = false; + if (field->is_constant()) { + SharkValue *value = SharkValue::from_ciConstant(field->constant_value()); + if (value != NULL) { + push(value->zero_checked()); + result_pushed = true; + } + } + + if (!result_pushed) { + if (!is_field) + return false; + + push(false); + } + + if (field->type()->is_two_word()) + push(false); + } + + return true; +} + +bool SharkInliner::attempt_inline(ciMethod *target, SharkState *state) +{ + if (may_be_inlinable(target)) { + SharkInlinerHelper inliner(target, state); + if (inliner.is_inlinable()) { + inliner.do_inline(); + return true; + } + } + return false; +} diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkInliner.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkInliner.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -0,0 +1,32 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class SharkInliner : public AllStatic { + public: + static bool attempt_inline(ciMethod* target, SharkState* state); + + private: + static bool may_be_inlinable(ciMethod* target); +}; diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkMonitor.cpp --- a/ports/hotspot/src/share/vm/shark/sharkMonitor.cpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkMonitor.cpp Wed Mar 04 10:41:13 2009 -0500 @@ -43,7 +43,7 @@ "displaced_header_addr"); } -void SharkMonitor::acquire(SharkBlock* block, Value *lockee) const +void SharkMonitor::acquire(SharkTopLevelBlock* block, Value *lockee) const { BasicBlock *try_recursive = function()->CreateBlock("try_recursive"); BasicBlock *got_recursive = function()->CreateBlock("got_recursive"); @@ -120,7 +120,7 @@ block->current_state()->merge(fast_state, acquired_fast, acquired_slow); } -void SharkMonitor::release(SharkBlock* block) const +void SharkMonitor::release(SharkTopLevelBlock* block) const { BasicBlock *not_recursive = function()->CreateBlock("not_recursive"); BasicBlock *released_fast = function()->CreateBlock("released_fast"); diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkMonitor.hpp --- a/ports/hotspot/src/share/vm/shark/sharkMonitor.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkMonitor.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -23,7 +23,7 @@ * */ -class SharkBlock; +class SharkTopLevelBlock; class SharkMonitor : public ResourceObj { public: @@ -89,6 +89,6 @@ } public: - void acquire(SharkBlock* block, llvm::Value* lockee) const; - void release(SharkBlock* block) const; + void acquire(SharkTopLevelBlock* block, llvm::Value* lockee) const; + void release(SharkTopLevelBlock* block) const; }; diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkState.cpp --- a/ports/hotspot/src/share/vm/shark/sharkState.cpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkState.cpp Wed Mar 04 10:41:13 2009 -0500 @@ -28,6 +28,24 @@ using namespace llvm; +SharkState::SharkState(SharkBlock* block, + SharkFunction* function, + llvm::Value* method) + : _block(block), + _function(function), + _method(method) +{ + initialize(NULL); +} + +SharkState::SharkState(const SharkState* state) + : _block(state->block()), + _function(state->function()), + _method(state->method()) +{ + initialize(state); +} + void SharkState::initialize(const SharkState *state) { _locals = NEW_RESOURCE_ARRAY(SharkValue*, max_locals()); @@ -45,177 +63,9 @@ NOT_PRODUCT(memset(_stack, 23, max_stack() * sizeof(SharkValue *))); } } - -void SharkEntryState::initialize(Value* method) -{ - char name[18]; - - // Method - set_method(method); - - // Local variables - for (int i = 0; i < max_locals(); i++) { - ciType *type = block()->local_type_at_entry(i); - - SharkValue *value = NULL; - switch (type->basic_type()) { - case T_INT: - case T_LONG: - case T_FLOAT: - case T_DOUBLE: - case T_OBJECT: - case T_ARRAY: - if (i < function()->arg_size()) { - snprintf(name, sizeof(name), "local_%d_", i); - value = SharkValue::create_generic( - type, - builder()->CreateLoad( - function()->CreateAddressOfFrameEntry( - function()->locals_slots_offset() - + max_locals() - type->size() - i, - SharkType::to_stackType(type)), - name)); - } - else { - Unimplemented(); - } - break; - - case ciTypeFlow::StateVector::T_BOTTOM: - break; - - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - - default: - ShouldNotReachHere(); - } - set_local(i, value); - } - - // Non-static methods have a guaranteed non-null receiver - if (!function()->target()->is_static()) { - assert(local(0)->is_jobject(), "should be"); - local(0)->set_zero_checked(true); - } - - // Expression stack - assert(!stack_depth_at_entry(), "entry block shouldn't have stack"); -} - -void SharkPHIState::initialize() -{ - BasicBlock *saved_insert_point = builder()->GetInsertBlock(); - builder()->SetInsertPoint(block()->entry_block()); - char name[18]; - - // Method - set_method(builder()->CreatePHI(SharkType::methodOop_type(), "method")); - - // Local variables - for (int i = 0; i < max_locals(); i++) { - ciType *type = block()->local_type_at_entry(i); - if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { - // XXX we could do all kinds of clever stuff here - type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? - } - - SharkValue *value = NULL; - switch (type->basic_type()) { - case T_INT: - case T_LONG: - case T_FLOAT: - case T_DOUBLE: - case T_OBJECT: - case T_ARRAY: - snprintf(name, sizeof(name), "local_%d_", i); - value = SharkValue::create_generic( - type, builder()->CreatePHI(SharkType::to_stackType(type), name)); - break; - - case T_ADDRESS: - value = SharkValue::create_returnAddress( - type->as_return_address()->bci()); - break; - - case ciTypeFlow::StateVector::T_BOTTOM: - break; - - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - - default: - ShouldNotReachHere(); - } - set_local(i, value); - } - - // Expression stack - for (int i = 0; i < stack_depth_at_entry(); i++) { - ciType *type = block()->stack_type_at_entry(i); - if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { - // XXX we could do all kinds of clever stuff here - type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? - } - - SharkValue *value = NULL; - switch (type->basic_type()) { - case T_INT: - case T_LONG: - case T_FLOAT: - case T_DOUBLE: - case T_OBJECT: - case T_ARRAY: - snprintf(name, sizeof(name), "stack_%d_", i); - value = SharkValue::create_generic( - type, builder()->CreatePHI(SharkType::to_stackType(type), name)); - break; - - case T_ADDRESS: - value = SharkValue::create_returnAddress( - type->as_return_address()->bci()); - break; - - case ciTypeFlow::StateVector::T_LONG2: - case ciTypeFlow::StateVector::T_DOUBLE2: - break; - - default: - ShouldNotReachHere(); - } - push(value); - } - - builder()->SetInsertPoint(saved_insert_point); -} - -void SharkPHIState::add_incoming(SharkState* incoming_state) -{ - BasicBlock *predecessor = builder()->GetInsertBlock(); - - // Method - ((PHINode *) method())->addIncoming(incoming_state->method(), predecessor); - - // Local variables - for (int i = 0; i < max_locals(); i++) { - if (local(i) != NULL) - local(i)->addIncoming(incoming_state->local(i), predecessor); - } - - // Expression stack - assert(stack_depth_at_entry() == incoming_state->stack_depth(), "should be"); - for (int i = 0; i < stack_depth_at_entry(); i++) { - assert((stack(i) == NULL) == (incoming_state->stack(i) == NULL), "oops"); - if (stack(i)) - stack(i)->addIncoming(incoming_state->stack(i), predecessor); - } -} - -void SharkTrackingState::merge(SharkState* other, - BasicBlock* other_block, - BasicBlock* this_block) +void SharkState::merge(SharkState* other, + BasicBlock* other_block, + BasicBlock* this_block) { PHINode *phi; char name[18]; @@ -269,16 +119,51 @@ } } -#ifndef PRODUCT -void SharkTrackingState::enter_inlined_section() +void SharkState::decache_for_Java_call(ciMethod* callee) { - assert(has_stack_frame(), "should do"); - set_has_stack_frame(false); + assert(function() && method(), "you cannot decache here"); + SharkJavaCallDecacher(function(), block()->bci(), callee).scan(this); + pop(callee->arg_size()); } -void SharkTrackingState::leave_inlined_section() +void SharkState::cache_after_Java_call(ciMethod* callee) { - assert(!has_stack_frame(), "shouldn't do"); - set_has_stack_frame(true); + assert(function() && method(), "you cannot cache here"); + if (callee->return_type()->size()) { + ciType *type; + switch (callee->return_type()->basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + type = ciType::make(T_INT); + break; + + default: + type = callee->return_type(); + } + + push(SharkValue::create_generic(type, NULL)); + if (type->is_two_word()) + push(NULL); + } + SharkJavaCallCacher(function(), block()->bci(), callee).scan(this); } -#endif // PRODUCT + +void SharkState::decache_for_VM_call() +{ + assert(function() && method(), "you cannot decache here"); + SharkVMCallDecacher(function(), block()->bci()).scan(this); +} + +void SharkState::cache_after_VM_call() +{ + assert(function() && method(), "you cannot cache here"); + SharkVMCallCacher(function(), block()->bci()).scan(this); +} + +void SharkState::decache_for_trap() +{ + assert(function() && method(), "you cannot decache here"); + SharkTrapDecacher(function(), block()->bci()).scan(this); +} diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkState.hpp --- a/ports/hotspot/src/share/vm/shark/sharkState.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkState.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -24,41 +24,41 @@ */ class SharkBlock; +class SharkFunction; class SharkState : public ResourceObj { - protected: - SharkState(SharkBlock* block) - : _block(block) { initialize(NULL); } - SharkState(const SharkState* state) - : _block(state->block()) { initialize(state); } + public: + SharkState(SharkBlock* block, + SharkFunction* function = NULL, + llvm::Value* method = NULL); + SharkState(const SharkState* state); private: void initialize(const SharkState* state); private: - SharkBlock* _block; + SharkBlock* _block; + SharkFunction* _function; + llvm::Value* _method; + SharkValue** _locals; + SharkValue** _stack; + SharkValue** _sp; public: SharkBlock *block() const { return _block; } - - protected: + SharkFunction *function() const + { + return _function; + } + + public: inline SharkBuilder* builder() const; - inline SharkFunction* function() const; - - public: inline int max_locals() const; inline int max_stack() const; - // The values we are tracking - private: - llvm::Value* _method; - SharkValue** _locals; - SharkValue** _stack; - SharkValue** _sp; - // Method public: llvm::Value** method_addr() @@ -125,75 +125,23 @@ { assert(stack_depth() >= slots, "stack underrun"); _sp -= slots; - } - inline int stack_depth_at_entry() const; -}; - -class SharkEntryState : public SharkState { - public: - SharkEntryState(llvm::Value* method, SharkBlock* start_block) - : SharkState(start_block) { initialize(method); } - - private: - void initialize(llvm::Value* method); -}; - -class SharkPHIState : public SharkState { - public: - SharkPHIState(SharkBlock* block) - : SharkState(block) { initialize(); } - - private: - void initialize(); - - public: - void add_incoming(SharkState* incoming_state); -}; - -class SharkTrackingState : public SharkState { - public: - SharkTrackingState(const SharkState* state) - : SharkState(state) - { - set_method(state->method()); - NOT_PRODUCT(set_has_stack_frame(true)); } - // Cache and decache - public: - inline void decache_for_Java_call(ciMethod* callee); - inline void cache_after_Java_call(ciMethod* callee); - inline void decache_for_VM_call(); - inline void cache_after_VM_call(); - inline void decache_for_trap(); - // Copy and merge public: - SharkTrackingState* copy() const + SharkState* copy() const { - return new SharkTrackingState(this); + return new SharkState(this); } void merge(SharkState* other, llvm::BasicBlock* other_block, llvm::BasicBlock* this_block); - // Inlining -#ifndef PRODUCT - private: - bool _has_stack_frame; - - protected: - bool has_stack_frame() const - { - return _has_stack_frame; - } - void set_has_stack_frame(bool has_stack_frame) - { - _has_stack_frame = has_stack_frame; - } -#endif // PRODUCT - + // Cache and decache public: - void enter_inlined_section() PRODUCT_RETURN; - void leave_inlined_section() PRODUCT_RETURN; + void decache_for_Java_call(ciMethod* callee); + void cache_after_Java_call(ciMethod* callee); + void decache_for_VM_call(); + void cache_after_VM_call(); + void decache_for_trap(); }; diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkState.inline.hpp --- a/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -28,11 +28,6 @@ return block()->builder(); } -inline SharkFunction* SharkState::function() const -{ - return block()->function(); -} - inline int SharkState::max_locals() const { return block()->max_locals(); @@ -42,57 +37,3 @@ { return block()->max_stack(); } - -inline int SharkState::stack_depth_at_entry() const -{ - return block()->stack_depth_at_entry(); -} - -inline void SharkTrackingState::decache_for_Java_call(ciMethod* callee) -{ - assert(has_stack_frame(), "should do"); - SharkJavaCallDecacher(function(), block()->bci(), callee).scan(this); - pop(callee->arg_size()); -} - -inline void SharkTrackingState::cache_after_Java_call(ciMethod* callee) -{ - assert(has_stack_frame(), "should do"); - if (callee->return_type()->size()) { - ciType *type; - switch (callee->return_type()->basic_type()) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_SHORT: - type = ciType::make(T_INT); - break; - - default: - type = callee->return_type(); - } - - push(SharkValue::create_generic(type, NULL)); - if (type->is_two_word()) - push(NULL); - } - SharkJavaCallCacher(function(), block()->bci(), callee).scan(this); -} - -inline void SharkTrackingState::decache_for_VM_call() -{ - assert(has_stack_frame(), "should do"); - SharkVMCallDecacher(function(), block()->bci()).scan(this); -} - -inline void SharkTrackingState::cache_after_VM_call() -{ - assert(has_stack_frame(), "should do"); - SharkVMCallCacher(function(), block()->bci()).scan(this); -} - -inline void SharkTrackingState::decache_for_trap() -{ - assert(has_stack_frame(), "should do"); - SharkTrapDecacher(function(), block()->bci()).scan(this); -} diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp Wed Mar 04 10:41:13 2009 -0500 @@ -0,0 +1,1716 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkTopLevelBlock.cpp.incl" +#include "ciArrayKlass.hpp" // XXX fuck you makeDeps +#include "ciObjArrayKlass.hpp" // XXX likewise + +using namespace llvm; + +class SharkPHIState : public SharkState { + public: + SharkPHIState(SharkTopLevelBlock* block) + : SharkState(block, block->function()) + { + BasicBlock *saved_insert_point = builder()->GetInsertBlock(); + builder()->SetInsertPoint(block->entry_block()); + char name[18]; + + // Method + set_method(builder()->CreatePHI(SharkType::methodOop_type(), "method")); + + // Local variables + for (int i = 0; i < max_locals(); i++) { + ciType *type = block->local_type_at_entry(i); + if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { + // XXX we could do all kinds of clever stuff here + type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? + } + + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + snprintf(name, sizeof(name), "local_%d_", i); + value = SharkValue::create_generic( + type, builder()->CreatePHI(SharkType::to_stackType(type), name)); + break; + + case T_ADDRESS: + value = SharkValue::create_returnAddress( + type->as_return_address()->bci()); + break; + + case ciTypeFlow::StateVector::T_BOTTOM: + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); + } + set_local(i, value); + } + + // Expression stack + for (int i = 0; i < block->stack_depth_at_entry(); i++) { + ciType *type = block->stack_type_at_entry(i); + if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { + // XXX we could do all kinds of clever stuff here + type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? + } + + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + snprintf(name, sizeof(name), "stack_%d_", i); + value = SharkValue::create_generic( + type, builder()->CreatePHI(SharkType::to_stackType(type), name)); + break; + + case T_ADDRESS: + value = SharkValue::create_returnAddress( + type->as_return_address()->bci()); + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); + } + push(value); + } + + builder()->SetInsertPoint(saved_insert_point); + } + + public: + void add_incoming(SharkState* incoming_state) + { + BasicBlock *predecessor = builder()->GetInsertBlock(); + + // Method + ((PHINode *) method())->addIncoming(incoming_state->method(), predecessor); + + // Local variables + for (int i = 0; i < max_locals(); i++) { + if (local(i) != NULL) + local(i)->addIncoming(incoming_state->local(i), predecessor); + } + + // Expression stack + int stack_depth = ((SharkTopLevelBlock *) block())->stack_depth_at_entry(); + assert(stack_depth == incoming_state->stack_depth(), "should be"); + for (int i = 0; i < stack_depth; i++) { + assert((stack(i) == NULL) == (incoming_state->stack(i) == NULL), "oops"); + if (stack(i)) + stack(i)->addIncoming(incoming_state->stack(i), predecessor); + } + } +}; + +SharkState* SharkTopLevelBlock::entry_state() +{ + if (_entry_state == NULL) { + assert(needs_phis(), "should do"); + _entry_state = new SharkPHIState(this); + } + return _entry_state; +} + +void SharkTopLevelBlock::add_incoming(SharkState* incoming_state) +{ + if (needs_phis()) { + ((SharkPHIState *) entry_state())->add_incoming(incoming_state); + } + else if (_entry_state != incoming_state) { + assert(_entry_state == NULL, "should be"); + _entry_state = incoming_state; + } +} + +void SharkTopLevelBlock::enter(SharkTopLevelBlock* predecessor, + bool is_exception) +{ + // This block requires phis: + // - if it is entered more than once + // - if it is an exception handler, because in which + // case we assume it's entered more than once. + // - if the predecessor will be compiled after this + // block, in which case we can't simple propagate + // the state forward. + if (!needs_phis() && + (entered() || + is_exception || + (predecessor && predecessor->index() >= index()))) + _needs_phis = true; + + // Recurse into the tree + if (!entered()) { + _entered = true; + + if (!has_trap()) { + for (int i = 0; i < num_successors(); i++) { + successor(i)->enter(this, false); + } + for (int i = 0; i < num_exceptions(); i++) { + exception(i)->enter(this, true); + } + } + } +} + +void SharkTopLevelBlock::initialize() +{ + char name[28]; + snprintf(name, sizeof(name), + "bci_%d%s", + start(), is_private_copy() ? "_private_copy" : ""); + _entry_block = function()->CreateBlock(name); +} + +void SharkTopLevelBlock::acquire_method_lock() +{ + Value *object; + if (target()->is_static()) { + SharkConstantPool constants(this); + object = constants.java_mirror(); + } + else { + object = local(0)->jobject_value(); + } + iter()->force_bci(start()); // for the decache + function()->monitor(0)->acquire(this, object); + check_pending_exception(false); +} + +void SharkTopLevelBlock::release_method_lock() +{ + function()->monitor(0)->release(this); + + // We neither need nor want to check for pending exceptions here. + // This method is only called by handle_return, which copes with + // them implicitly: + // - if a value is being returned then we just carry on as normal; + // the caller will see the pending exception and handle it. + // - if an exception is being thrown then that exception takes + // priority and ours will be ignored. +} + +void SharkTopLevelBlock::emit_IR() +{ + builder()->SetInsertPoint(entry_block()); + + // Handle traps + if (has_trap()) { + iter()->force_bci(start()); + + current_state()->decache_for_trap(); + builder()->CreateCall2( + SharkRuntime::uncommon_trap(), + thread(), + LLVMValue::jint_constant(trap_index())); + builder()->CreateRetVoid(); + return; + } + + // Parse the bytecode + parse_bytecode(start(), limit()); + + // If this block falls through to the next then it won't have been + // terminated by a bytecode and we have to add the branch ourselves + if (falls_through()) { + builder()->CreateBr(successor(ciTypeFlow::FALL_THROUGH)->entry_block()); + } + + // Process the successor states if not already done + switch (bc()) { + case Bytecodes::_tableswitch: + case Bytecodes::_lookupswitch: + // done by do_switch() + break; + + default: + for (int i = 0; i < num_successors(); i++) + successor(i)->add_incoming(current_state()); + } +} + +SharkTopLevelBlock* SharkTopLevelBlock::bci_successor(int bci) const +{ + // XXX now with Linear Search Technology (tm) + for (int i = 0; i < num_successors(); i++) { + ciTypeFlow::Block *successor = ciblock()->successors()->at(i); + if (successor->start() == bci) + return function()->block(successor->pre_order()); + } + ShouldNotReachHere(); +} + +void SharkTopLevelBlock::do_zero_check(SharkValue *value) +{ + BasicBlock *zero = function()->CreateBlock("zero"); + BasicBlock *not_zero = function()->CreateBlock("not_zero"); + + Value *a, *b; + switch (value->basic_type()) { + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + a = value->jint_value(); + b = LLVMValue::jint_constant(0); + break; + case T_LONG: + a = value->jlong_value(); + b = LLVMValue::jlong_constant(0); + break; + case T_OBJECT: + case T_ARRAY: + a = value->jobject_value(); + b = LLVMValue::LLVMValue::null(); + break; + default: + tty->print_cr("Unhandled type %s", type2name(value->basic_type())); + ShouldNotReachHere(); + } + + builder()->CreateCondBr(builder()->CreateICmpNE(a, b), not_zero, zero); + + builder()->SetInsertPoint(zero); + SharkState *saved_state = current_state()->copy(); + if (value->is_jobject()) { + call_vm_nocheck( + SharkRuntime::throw_NullPointerException(), + builder()->pointer_constant(__FILE__), + LLVMValue::jint_constant(__LINE__)); + } + else { + builder()->CreateUnimplemented(__FILE__, __LINE__); + } + handle_exception(function()->CreateGetPendingException()); + set_current_state(saved_state); + + builder()->SetInsertPoint(not_zero); + + value->set_zero_checked(true); +} + +void SharkTopLevelBlock::check_bounds(SharkValue* array, SharkValue* index) +{ + BasicBlock *out_of_bounds = function()->CreateBlock("out_of_bounds"); + BasicBlock *in_bounds = function()->CreateBlock("in_bounds"); + + Value *length = builder()->CreateArrayLength(array->jarray_value()); + // we use an unsigned comparison to catch negative values + builder()->CreateCondBr( + builder()->CreateICmpULT(index->jint_value(), length), + in_bounds, out_of_bounds); + + builder()->SetInsertPoint(out_of_bounds); + SharkState *saved_state = current_state()->copy(); + call_vm_nocheck( + SharkRuntime::throw_ArrayIndexOutOfBoundsException(), + builder()->pointer_constant(__FILE__), + LLVMValue::jint_constant(__LINE__), + index->jint_value()); + handle_exception(function()->CreateGetPendingException()); + set_current_state(saved_state); + + builder()->SetInsertPoint(in_bounds); +} + +void SharkTopLevelBlock::check_pending_exception(bool attempt_catch) +{ + BasicBlock *exception = function()->CreateBlock("exception"); + BasicBlock *no_exception = function()->CreateBlock("no_exception"); + + Value *pending_exception_addr = function()->pending_exception_address(); + Value *pending_exception = builder()->CreateLoad( + pending_exception_addr, "pending_exception"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ(pending_exception, LLVMValue::null()), + no_exception, exception); + + builder()->SetInsertPoint(exception); + builder()->CreateStore(LLVMValue::null(), pending_exception_addr); + SharkState *saved_state = current_state()->copy(); + handle_exception(pending_exception, attempt_catch); + set_current_state(saved_state); + + builder()->SetInsertPoint(no_exception); +} + +void SharkTopLevelBlock::handle_exception(Value* exception, bool attempt_catch) +{ + if (attempt_catch && num_exceptions() != 0) { + // Clear the stack and push the exception onto it. + // We do this now to protect it across the VM call + // we may be about to make. + while (xstack_depth()) + pop(); + push(SharkValue::create_jobject(exception)); + + int *indexes = NEW_RESOURCE_ARRAY(int, num_exceptions()); + bool has_catch_all = false; + + ciExceptionHandlerStream eh_iter(target(), bci()); + for (int i = 0; i < num_exceptions(); i++, eh_iter.next()) { + ciExceptionHandler* handler = eh_iter.handler(); + + if (handler->is_catch_all()) { + assert(i == num_exceptions() - 1, "catch-all should be last"); + has_catch_all = true; + } + else { + indexes[i] = handler->catch_klass_index(); + } + } + + int num_options = num_exceptions(); + if (has_catch_all) + num_options--; + + // Drop into the runtime if there are non-catch-all options + if (num_options > 0) { + Value *options = builder()->CreateAlloca( + ArrayType::get(SharkType::jint_type(), num_options), + LLVMValue::jint_constant(1)); + + for (int i = 0; i < num_options; i++) + builder()->CreateStore( + LLVMValue::jint_constant(indexes[i]), + builder()->CreateStructGEP(options, i)); + + Value *index = call_vm_nocheck( + SharkRuntime::find_exception_handler(), + builder()->CreateStructGEP(options, 0), + LLVMValue::jint_constant(num_options)); + check_pending_exception(false); + + // Jump to the exception handler, if found + BasicBlock *no_handler = function()->CreateBlock("no_handler"); + SwitchInst *switchinst = builder()->CreateSwitch( + index, no_handler, num_options); + + for (int i = 0; i < num_options; i++) { + SharkTopLevelBlock* handler = this->exception(i); + + switchinst->addCase( + LLVMValue::jint_constant(i), + handler->entry_block()); + + handler->add_incoming(current_state()); + } + + builder()->SetInsertPoint(no_handler); + } + + // No specific handler exists, but maybe there's a catch-all + if (has_catch_all) { + SharkTopLevelBlock* handler = this->exception(num_options); + + builder()->CreateBr(handler->entry_block()); + handler->add_incoming(current_state()); + return; + } + } + + // No exception handler was found; unwind and return + handle_return(T_VOID, exception); +} + +void SharkTopLevelBlock::add_safepoint() +{ + BasicBlock *orig_block = builder()->GetInsertBlock(); + SharkState *orig_state = current_state()->copy(); + + BasicBlock *do_safepoint = function()->CreateBlock("do_safepoint"); + BasicBlock *safepointed = function()->CreateBlock("safepointed"); + + Value *state = builder()->CreateLoad( + builder()->CreateIntToPtr( + builder()->pointer_constant(SafepointSynchronize::address_of_state()), + PointerType::getUnqual(SharkType::jint_type())), + "state"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ( + state, + LLVMValue::jint_constant(SafepointSynchronize::_synchronizing)), + do_safepoint, safepointed); + + builder()->SetInsertPoint(do_safepoint); + call_vm(SharkRuntime::safepoint()); + BasicBlock *safepointed_block = builder()->GetInsertBlock(); + builder()->CreateBr(safepointed); + + builder()->SetInsertPoint(safepointed); + current_state()->merge(orig_state, orig_block, safepointed_block); +} + +void SharkTopLevelBlock::call_register_finalizer(Value *receiver) +{ + BasicBlock *orig_block = builder()->GetInsertBlock(); + SharkState *orig_state = current_state()->copy(); + + BasicBlock *do_call = function()->CreateBlock("has_finalizer"); + BasicBlock *done = function()->CreateBlock("done"); + + Value *klass = builder()->CreateValueOfStructEntry( + receiver, + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::jobject_type(), + "klass"); + + Value *klass_part = builder()->CreateAddressOfStructEntry( + klass, + in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()), + SharkType::klass_type(), + "klass_part"); + + Value *access_flags = builder()->CreateValueOfStructEntry( + klass_part, + in_ByteSize(Klass::access_flags_offset_in_bytes()), + SharkType::jint_type(), + "access_flags"); + + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateAnd( + access_flags, + LLVMValue::jint_constant(JVM_ACC_HAS_FINALIZER)), + LLVMValue::jint_constant(0)), + do_call, done); + + builder()->SetInsertPoint(do_call); + call_vm(SharkRuntime::register_finalizer(), receiver); + BasicBlock *branch_block = builder()->GetInsertBlock(); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + current_state()->merge(orig_state, orig_block, branch_block); +} + +void SharkTopLevelBlock::handle_return(BasicType type, Value* exception) +{ + assert (exception == NULL || type == T_VOID, "exception OR result, please"); + + if (exception) + builder()->CreateStore(exception, function()->exception_slot()); + + release_locked_monitors(); + if (target()->is_synchronized()) + release_method_lock(); + + if (exception) { + exception = builder()->CreateLoad(function()->exception_slot()); + builder()->CreateStore(exception, function()->pending_exception_address()); + } + + Value *result_addr = function()->CreatePopFrame(type2size[type]); + if (type != T_VOID) { + builder()->CreateStore( + pop_result(type)->generic_value(), + builder()->CreateIntToPtr( + result_addr, + PointerType::getUnqual(SharkType::to_stackType(type)))); + } + + builder()->CreateRetVoid(); +} + +void SharkTopLevelBlock::release_locked_monitors() +{ + int base = target()->is_synchronized(); + for (int i = function()->monitor_count() - 1; i >= base; i--) { + BasicBlock *locked = function()->CreateBlock("locked"); + BasicBlock *unlocked = function()->CreateBlock("unlocked"); + + Value *object = function()->monitor(i)->object(); + builder()->CreateCondBr( + builder()->CreateICmpNE(object, LLVMValue::null()), + locked, unlocked); + + builder()->SetInsertPoint(locked); + builder()->CreateUnimplemented(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + builder()->SetInsertPoint(unlocked); + } +} + +Value *SharkTopLevelBlock::lookup_for_ldc() +{ + SharkConstantPool constants(this); + + BasicBlock *resolved = function()->CreateBlock("resolved"); + BasicBlock *resolved_class = function()->CreateBlock("resolved_class"); + BasicBlock *unresolved = function()->CreateBlock("unresolved"); + BasicBlock *unknown = function()->CreateBlock("unknown"); + BasicBlock *done = function()->CreateBlock("done"); + + SwitchInst *switchinst = builder()->CreateSwitch( + constants.tag_at(iter()->get_constant_index()), + unknown, 5); + + switchinst->addCase( + LLVMValue::jbyte_constant(JVM_CONSTANT_String), resolved); + switchinst->addCase( + LLVMValue::jbyte_constant(JVM_CONSTANT_Class), resolved_class); + switchinst->addCase( + LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedString), unresolved); + switchinst->addCase( + LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClass), unresolved); + switchinst->addCase( + LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClassInError), + unresolved); + + builder()->SetInsertPoint(resolved); + Value *resolved_value = constants.object_at(iter()->get_constant_index()); + builder()->CreateBr(done); + + builder()->SetInsertPoint(resolved_class); + Value *resolved_class_value + = constants.object_at(iter()->get_constant_index()); + resolved_class_value + = builder()->CreatePtrToInt(resolved_class_value, + SharkType::intptr_type()); + resolved_class_value + = (builder()->CreateAdd + (resolved_class_value, + (LLVMValue::intptr_constant + (klassOopDesc::klass_part_offset_in_bytes() + + Klass::java_mirror_offset_in_bytes())))); + // XXX FIXME: We need a memory barrier before this load. + resolved_class_value + = (builder()->CreateLoad + (builder()->CreateIntToPtr + (resolved_class_value, + PointerType::getUnqual(SharkType::jobject_type())))); + builder()->CreateBr(done); + + builder()->SetInsertPoint(unresolved); + builder()->CreateUnimplemented(__FILE__, __LINE__); + Value *unresolved_value = LLVMValue::null(); + builder()->CreateBr(done); + + builder()->SetInsertPoint(unknown); + builder()->CreateShouldNotReachHere(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + builder()->SetInsertPoint(done); + PHINode *phi = builder()->CreatePHI(SharkType::jobject_type(), "constant"); + phi->addIncoming(resolved_value, resolved); + phi->addIncoming(resolved_class_value, resolved_class); + phi->addIncoming(unresolved_value, unresolved); + return phi; +} + +Value* SharkTopLevelBlock::lookup_for_field_access() +{ + SharkConstantPool constants(this); + Value *cache = constants.cache_entry_at(iter()->get_field_index()); + + return builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f1_offset(), + SharkType::jobject_type(), + "object"); +} + +void SharkTopLevelBlock::do_arraylength() +{ + SharkValue *array = pop(); + check_null(array); + Value *length = builder()->CreateArrayLength(array->jarray_value()); + push(SharkValue::create_jint(length)); +} + +void SharkTopLevelBlock::do_aload(BasicType basic_type) +{ + SharkValue *index = pop(); + SharkValue *array = pop(); + + assert(array->type()->is_array_klass(), "should be"); + ciType *element_type = ((ciArrayKlass *) array->type())->element_type(); + assert((element_type->basic_type() == T_BOOLEAN && basic_type == T_BYTE) || + (element_type->basic_type() == T_ARRAY && basic_type == T_OBJECT) || + (element_type->basic_type() == basic_type), "type mismatch"); + + check_null(array); + check_bounds(array, index); + + Value *value = builder()->CreateLoad( + builder()->CreateArrayAddress( + array->jarray_value(), basic_type, index->jint_value())); + + const Type *stack_type = SharkType::to_stackType(basic_type); + if (value->getType() != stack_type) + value = builder()->CreateIntCast(value, stack_type, basic_type != T_CHAR); + + switch (basic_type) { + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + push(SharkValue::create_jint(value)); + break; + + case T_LONG: + push(SharkValue::create_jlong(value)); + break; + + case T_FLOAT: + push(SharkValue::create_jfloat(value)); + break; + + case T_DOUBLE: + push(SharkValue::create_jdouble(value)); + break; + + case T_OBJECT: + push(SharkValue::create_generic(element_type, value)); + break; + + default: + tty->print_cr("Unhandled type %s", type2name(basic_type)); + ShouldNotReachHere(); + } +} + +void SharkTopLevelBlock::do_astore(BasicType basic_type) +{ + SharkValue *svalue = pop(); + SharkValue *index = pop(); + SharkValue *array = pop(); + + assert(array->type()->is_array_klass(), "should be"); + ciType *element_type = ((ciArrayKlass *) array->type())->element_type(); + assert((element_type->basic_type() == T_BOOLEAN && basic_type == T_BYTE) || + (element_type->basic_type() == T_ARRAY && basic_type == T_OBJECT) || + (element_type->basic_type() == basic_type), "type mismatch"); + + check_null(array); + check_bounds(array, index); + + Value *value; + switch (basic_type) { + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + value = svalue->jint_value(); + break; + + case T_LONG: + value = svalue->jlong_value(); + break; + + case T_FLOAT: + value = svalue->jfloat_value(); + break; + + case T_DOUBLE: + value = svalue->jdouble_value(); + break; + + case T_OBJECT: + value = svalue->jobject_value(); + // XXX assignability check + break; + + default: + tty->print_cr("Unhandled type %s", type2name(basic_type)); + ShouldNotReachHere(); + } + + const Type *array_type = SharkType::to_arrayType(basic_type); + if (value->getType() != array_type) + value = builder()->CreateIntCast(value, array_type, basic_type != T_CHAR); + + Value *addr = builder()->CreateArrayAddress( + array->jarray_value(), basic_type, index->jint_value(), "addr"); + + builder()->CreateStore(value, addr); + + if (!element_type->is_primitive_type()) + builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); +} + +void SharkTopLevelBlock::do_return(BasicType type) +{ + if (target()->intrinsic_id() == vmIntrinsics::_Object_init) + call_register_finalizer(local(0)->jobject_value()); + else + add_safepoint(); + handle_return(type, NULL); +} + +void SharkTopLevelBlock::do_athrow() +{ + SharkValue *exception = pop(); + check_null(exception); + handle_exception(exception->jobject_value()); +} + +void SharkTopLevelBlock::do_goto() +{ + builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); +} + +void SharkTopLevelBlock::do_jsr() +{ + push(SharkValue::create_returnAddress(iter()->next_bci())); + builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); +} + +void SharkTopLevelBlock::do_ret() +{ + assert(local(iter()->get_index())->returnAddress_value() == + successor(ciTypeFlow::GOTO_TARGET)->start(), "should be"); + builder()->CreateBr(successor(ciTypeFlow::GOTO_TARGET)->entry_block()); +} + +void SharkTopLevelBlock::do_if(ICmpInst::Predicate p, SharkValue *b, SharkValue *a) +{ + Value *llvm_a, *llvm_b; + if (a->is_jobject()) { + llvm_a = a->intptr_value(builder()); + llvm_b = b->intptr_value(builder()); + } + else { + llvm_a = a->jint_value(); + llvm_b = b->jint_value(); + } + + builder()->CreateCondBr( + builder()->CreateICmp(p, llvm_a, llvm_b), + successor(ciTypeFlow::IF_TAKEN)->entry_block(), + successor(ciTypeFlow::IF_NOT_TAKEN)->entry_block()); +} + +void SharkTopLevelBlock::do_switch() +{ + int len = switch_table_length(); + + SharkTopLevelBlock *dest_block = successor(ciTypeFlow::SWITCH_DEFAULT); + SwitchInst *switchinst = builder()->CreateSwitch( + pop()->jint_value(), dest_block->entry_block(), len); + dest_block->add_incoming(current_state()); + + for (int i = 0; i < len; i++) { + int dest_bci = switch_dest(i); + if (dest_bci != switch_default_dest()) { + dest_block = bci_successor(dest_bci); + switchinst->addCase( + LLVMValue::jint_constant(switch_key(i)), + dest_block->entry_block()); + dest_block->add_incoming(current_state()); + } + } +} + +// Figure out what type of call this is. +// - Direct calls are where the callee is fixed. +// - Interface and Virtual calls require lookup at runtime. +// NB some invokevirtuals can be resolved to direct calls. +SharkTopLevelBlock::CallType SharkTopLevelBlock::get_call_type(ciMethod* method) +{ + if (bc() == Bytecodes::_invokeinterface) + return CALL_INTERFACE; + else if (bc() == Bytecodes::_invokevirtual && !method->is_final_method()) + return CALL_VIRTUAL; + else + return CALL_DIRECT; +} + +Value *SharkTopLevelBlock::get_callee(CallType call_type, + ciMethod* method, + SharkValue* receiver) +{ + switch (call_type) { + case CALL_DIRECT: + return get_direct_callee(method); + case CALL_VIRTUAL: + return get_virtual_callee(receiver, method); + case CALL_INTERFACE: + return get_interface_callee(receiver); + default: + ShouldNotReachHere(); + } +} + +// Direct calls can be made when the callee is fixed. +// invokestatic and invokespecial are always direct; +// invokevirtual is direct in some circumstances. +Value *SharkTopLevelBlock::get_direct_callee(ciMethod* method) +{ + SharkConstantPool constants(this); + Value *cache = constants.cache_entry_at(iter()->get_method_index()); + return builder()->CreateValueOfStructEntry( + cache, + bc() == Bytecodes::_invokevirtual ? + ConstantPoolCacheEntry::f2_offset() : + ConstantPoolCacheEntry::f1_offset(), + SharkType::methodOop_type(), + "callee"); +} + +// Non-direct virtual calls are handled here +Value *SharkTopLevelBlock::get_virtual_callee(SharkValue* receiver, + ciMethod* method) +{ + Value *klass = builder()->CreateValueOfStructEntry( + receiver->jobject_value(), + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::jobject_type(), + "klass"); + + Value *index; + if (!method->holder()->is_linked()) { + // Yuck, we have to do this one slow :( + // XXX should we trap on this? + NOT_PRODUCT(warning("unresolved invokevirtual in %s", function()->name())); + SharkConstantPool constants(this); + Value *cache = constants.cache_entry_at(iter()->get_method_index()); + index = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f2_offset(), + SharkType::intptr_type(), + "index"); + } + else { + index = LLVMValue::intptr_constant(method->vtable_index()); + } + + return builder()->CreateLoad( + builder()->CreateArrayAddress( + klass, + SharkType::methodOop_type(), + vtableEntry::size() * wordSize, + in_ByteSize(instanceKlass::vtable_start_offset() * wordSize), + index), + "callee"); +} + +// Interpreter-style virtual call lookup +Value* SharkTopLevelBlock::get_virtual_callee(Value *cache, SharkValue *receiver) +{ + BasicBlock *final = function()->CreateBlock("final"); + BasicBlock *not_final = function()->CreateBlock("not_final"); + BasicBlock *got_callee = function()->CreateBlock("got_callee"); + + Value *flags = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::flags_offset(), + SharkType::intptr_type(), + "flags"); + + const int mask = 1 << ConstantPoolCacheEntry::vfinalMethod; + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), + LLVMValue::intptr_constant(0)), + final, not_final); + + // For final methods f2 is the actual address of the method + builder()->SetInsertPoint(final); + Value *final_callee = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f2_offset(), + SharkType::methodOop_type(), + "final_callee"); + builder()->CreateBr(got_callee); + + // For non-final methods f2 is the index into the vtable + builder()->SetInsertPoint(not_final); + Value *klass = builder()->CreateValueOfStructEntry( + receiver->jobject_value(), + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::jobject_type(), + "klass"); + + Value *index = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f2_offset(), + SharkType::intptr_type(), + "index"); + + Value *nonfinal_callee = builder()->CreateLoad( + builder()->CreateArrayAddress( + klass, + SharkType::methodOop_type(), + vtableEntry::size() * wordSize, + in_ByteSize(instanceKlass::vtable_start_offset() * wordSize), + index), + "nonfinal_callee"); + builder()->CreateBr(got_callee); + + builder()->SetInsertPoint(got_callee); + PHINode *callee = builder()->CreatePHI( + SharkType::methodOop_type(), "callee"); + callee->addIncoming(final_callee, final); + callee->addIncoming(nonfinal_callee, not_final); + + return callee; +} + +// Interpreter-style interface call lookup +Value* SharkTopLevelBlock::get_interface_callee(SharkValue *receiver) +{ + SharkConstantPool constants(this); + Value *cache = constants.cache_entry_at(iter()->get_method_index()); + + BasicBlock *hacky = function()->CreateBlock("hacky"); + BasicBlock *normal = function()->CreateBlock("normal"); + BasicBlock *loop = function()->CreateBlock("loop"); + BasicBlock *got_null = function()->CreateBlock("got_null"); + BasicBlock *not_null = function()->CreateBlock("not_null"); + BasicBlock *next = function()->CreateBlock("next"); + BasicBlock *got_entry = function()->CreateBlock("got_entry"); + BasicBlock *got_callee = function()->CreateBlock("got_callee"); + + Value *flags = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::flags_offset(), + SharkType::intptr_type(), + "flags"); + + const int mask = 1 << ConstantPoolCacheEntry::methodInterface; + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateAnd(flags, LLVMValue::intptr_constant(mask)), + LLVMValue::intptr_constant(0)), + hacky, normal); + + // Workaround for the case where we encounter an invokeinterface, + // but should really have an invokevirtual since the resolved + // method is a virtual method in java.lang.Object. This is a + // corner case in the spec but is presumably legal, and while + // javac does not generate this code there's no reason it could + // not be produced by a compliant java compiler. See + // cpCacheOop.cpp for more details. + builder()->SetInsertPoint(hacky); + Value *hacky_callee = get_virtual_callee(cache, receiver); + BasicBlock *got_hacky = builder()->GetInsertBlock(); + builder()->CreateBr(got_callee); + + // Locate the receiver's itable + builder()->SetInsertPoint(normal); + Value *object_klass = builder()->CreateValueOfStructEntry( + receiver->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::jobject_type(), + "object_klass"); + + Value *vtable_start = builder()->CreateAdd( + builder()->CreatePtrToInt(object_klass, SharkType::intptr_type()), + LLVMValue::intptr_constant( + instanceKlass::vtable_start_offset() * HeapWordSize), + "vtable_start"); + + Value *vtable_length = builder()->CreateValueOfStructEntry( + object_klass, + in_ByteSize(instanceKlass::vtable_length_offset() * HeapWordSize), + SharkType::jint_type(), + "vtable_length"); + vtable_length = + builder()->CreateIntCast(vtable_length, SharkType::intptr_type(), false); + + bool needs_aligning = HeapWordsPerLong > 1; + const char *itable_start_name = "itable_start"; + Value *itable_start = builder()->CreateAdd( + vtable_start, + builder()->CreateShl( + vtable_length, + LLVMValue::intptr_constant(exact_log2(vtableEntry::size() * wordSize))), + needs_aligning ? "" : itable_start_name); + if (needs_aligning) + itable_start = builder()->CreateAlign( + itable_start, BytesPerLong, itable_start_name); + + // Locate this interface's entry in the table + Value *iklass = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f1_offset(), + SharkType::jobject_type(), + "iklass"); + + builder()->CreateBr(loop); + builder()->SetInsertPoint(loop); + PHINode *itable_entry_addr = builder()->CreatePHI( + SharkType::intptr_type(), "itable_entry_addr"); + itable_entry_addr->addIncoming(itable_start, normal); + + Value *itable_entry = builder()->CreateIntToPtr( + itable_entry_addr, SharkType::itableOffsetEntry_type(), "itable_entry"); + + Value *itable_iklass = builder()->CreateValueOfStructEntry( + itable_entry, + in_ByteSize(itableOffsetEntry::interface_offset_in_bytes()), + SharkType::jobject_type(), + "itable_iklass"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ(itable_iklass, LLVMValue::null()), + got_null, not_null); + + // A null entry means that the class doesn't implement the + // interface, and wasn't the same as the class checked when + // the interface was resolved. + builder()->SetInsertPoint(got_null); + builder()->CreateUnimplemented(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + builder()->SetInsertPoint(not_null); + builder()->CreateCondBr( + builder()->CreateICmpEQ(itable_iklass, iklass), + got_entry, next); + + builder()->SetInsertPoint(next); + Value *next_entry = builder()->CreateAdd( + itable_entry_addr, + LLVMValue::intptr_constant(itableOffsetEntry::size() * wordSize)); + builder()->CreateBr(loop); + itable_entry_addr->addIncoming(next_entry, next); + + // Locate the method pointer + builder()->SetInsertPoint(got_entry); + Value *offset = builder()->CreateValueOfStructEntry( + itable_entry, + in_ByteSize(itableOffsetEntry::offset_offset_in_bytes()), + SharkType::jint_type(), + "offset"); + offset = + builder()->CreateIntCast(offset, SharkType::intptr_type(), false); + + Value *index = builder()->CreateValueOfStructEntry( + cache, ConstantPoolCacheEntry::f2_offset(), + SharkType::intptr_type(), + "index"); + + Value *normal_callee = builder()->CreateLoad( + builder()->CreateIntToPtr( + builder()->CreateAdd( + builder()->CreateAdd( + builder()->CreateAdd( + builder()->CreatePtrToInt( + object_klass, SharkType::intptr_type()), + offset), + builder()->CreateShl( + index, + LLVMValue::intptr_constant( + exact_log2(itableMethodEntry::size() * wordSize)))), + LLVMValue::intptr_constant( + itableMethodEntry::method_offset_in_bytes())), + PointerType::getUnqual(SharkType::methodOop_type())), + "normal_callee"); + BasicBlock *got_normal = builder()->GetInsertBlock(); + builder()->CreateBr(got_callee); + + builder()->SetInsertPoint(got_callee); + PHINode *callee = builder()->CreatePHI( + SharkType::methodOop_type(), "callee"); + callee->addIncoming(hacky_callee, got_hacky); + callee->addIncoming(normal_callee, got_normal); + + return callee; +} + +void SharkTopLevelBlock::do_call() +{ + bool will_link; + ciMethod *method = iter()->get_method(will_link); + assert(will_link, "typeflow responsibility"); + + // Figure out what type of call this is + CallType call_type = get_call_type(method); + + // Find the receiver in the stack. We do this before + // trying to inline because the inliner can only use + // zero-checked values, not being able to perform the + // check itself. + SharkValue *receiver = NULL; + if (bc() != Bytecodes::_invokestatic) { + receiver = xstack(method->arg_size() - 1); + check_null(receiver); + } + + // Try to inline the call + if (call_type == CALL_DIRECT) { + if (SharkInliner::attempt_inline(method, current_state())) + return; + } + + // Find the method we are calling + Value *callee = get_callee(call_type, method, receiver); + + // Load the SharkEntry from the callee + Value *base_pc = builder()->CreateValueOfStructEntry( + callee, methodOopDesc::from_interpreted_offset(), + SharkType::intptr_type(), + "base_pc"); + + // Load the entry point from the SharkEntry + Value *entry_point = builder()->CreateLoad( + builder()->CreateIntToPtr( + builder()->CreateAdd( + base_pc, + LLVMValue::intptr_constant(in_bytes(ZeroEntry::entry_point_offset()))), + PointerType::getUnqual( + PointerType::getUnqual(SharkType::entry_point_type()))), + "entry_point"); + + // Make the call + current_state()->decache_for_Java_call(method); + builder()->CreateCall3(entry_point, callee, base_pc, thread()); + current_state()->cache_after_Java_call(method); + + // Check for pending exceptions + check_pending_exception(); +} + +void SharkTopLevelBlock::do_instance_check() +{ + // Leave the object on the stack until after all the VM calls + assert(xstack(0)->is_jobject(), "should be"); + + ciKlass *klass = NULL; + if (bc() == Bytecodes::_checkcast) { + bool will_link; + klass = iter()->get_klass(will_link); + if (!will_link) { + // XXX why is this not typeflow's responsibility? + NOT_PRODUCT(warning("unresolved checkcast in %s", function()->name())); + klass = (ciKlass *) xstack(0)->type(); + } + } + + BasicBlock *not_null = function()->CreateBlock("not_null"); + BasicBlock *fast_path = function()->CreateBlock("fast_path"); + BasicBlock *slow_path = function()->CreateBlock("slow_path"); + BasicBlock *got_klass = function()->CreateBlock("got_klass"); + BasicBlock *subtype_check = function()->CreateBlock("subtype_check"); + BasicBlock *is_instance = function()->CreateBlock("is_instance"); + BasicBlock *not_instance = function()->CreateBlock("not_instance"); + BasicBlock *merge1 = function()->CreateBlock("merge1"); + BasicBlock *merge2 = function()->CreateBlock("merge2"); + + enum InstanceCheckStates { + IC_IS_NULL, + IC_IS_INSTANCE, + IC_NOT_INSTANCE, + }; + + // Null objects aren't instances of anything + builder()->CreateCondBr( + builder()->CreateICmpEQ(xstack(0)->jobject_value(), LLVMValue::null()), + merge2, not_null); + BasicBlock *null_block = builder()->GetInsertBlock(); + SharkState *null_state = current_state()->copy(); + + // Get the class we're checking against + builder()->SetInsertPoint(not_null); + SharkConstantPool constants(this); + Value *tag = constants.tag_at(iter()->get_klass_index()); + builder()->CreateCondBr( + builder()->CreateOr( + builder()->CreateICmpEQ( + tag, LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClass)), + builder()->CreateICmpEQ( + tag, LLVMValue::jbyte_constant(JVM_CONSTANT_UnresolvedClassInError))), + slow_path, fast_path); + + // The fast path + builder()->SetInsertPoint(fast_path); + BasicBlock *fast_block = builder()->GetInsertBlock(); + SharkState *fast_state = current_state()->copy(); + Value *fast_klass = constants.object_at(iter()->get_klass_index()); + builder()->CreateBr(got_klass); + + // The slow path + builder()->SetInsertPoint(slow_path); + call_vm( + SharkRuntime::resolve_klass(), + LLVMValue::jint_constant(iter()->get_klass_index())); + Value *slow_klass = function()->CreateGetVMResult(); + BasicBlock *slow_block = builder()->GetInsertBlock(); + builder()->CreateBr(got_klass); + + // We have the class to test against + builder()->SetInsertPoint(got_klass); + current_state()->merge(fast_state, fast_block, slow_block); + PHINode *check_klass = builder()->CreatePHI( + SharkType::jobject_type(), "check_klass"); + check_klass->addIncoming(fast_klass, fast_block); + check_klass->addIncoming(slow_klass, slow_block); + + // Get the class of the object being tested + Value *object_klass = builder()->CreateValueOfStructEntry( + xstack(0)->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::jobject_type(), + "object_klass"); + + // Perform the check + builder()->CreateCondBr( + builder()->CreateICmpEQ(check_klass, object_klass), + is_instance, subtype_check); + + builder()->SetInsertPoint(subtype_check); + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateCall2( + SharkRuntime::is_subtype_of(), check_klass, object_klass), + LLVMValue::jbyte_constant(0)), + is_instance, not_instance); + + builder()->SetInsertPoint(is_instance); + builder()->CreateBr(merge1); + + builder()->SetInsertPoint(not_instance); + builder()->CreateBr(merge1); + + // First merge + builder()->SetInsertPoint(merge1); + PHINode *nonnull_result = builder()->CreatePHI( + SharkType::jint_type(), "nonnull_result"); + nonnull_result->addIncoming( + LLVMValue::jint_constant(IC_IS_INSTANCE), is_instance); + nonnull_result->addIncoming( + LLVMValue::jint_constant(IC_NOT_INSTANCE), not_instance); + BasicBlock *nonnull_block = builder()->GetInsertBlock(); + builder()->CreateBr(merge2); + + // Second merge + builder()->SetInsertPoint(merge2); + current_state()->merge(null_state, null_block, nonnull_block); + PHINode *result = builder()->CreatePHI( + SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(IC_IS_NULL), null_block); + result->addIncoming(nonnull_result, nonnull_block); + + // We can finally pop the object! + Value *object = pop()->jobject_value(); + + // Handle the result + if (bc() == Bytecodes::_checkcast) { + BasicBlock *failure = function()->CreateBlock("failure"); + BasicBlock *success = function()->CreateBlock("success"); + + builder()->CreateCondBr( + builder()->CreateICmpNE( + result, LLVMValue::jint_constant(IC_NOT_INSTANCE)), + success, failure); + + builder()->SetInsertPoint(failure); + builder()->CreateUnimplemented(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + builder()->SetInsertPoint(success); + push(SharkValue::create_generic(klass, object)); + } + else { + push( + SharkValue::create_jint( + builder()->CreateIntCast( + builder()->CreateICmpEQ( + result, LLVMValue::jint_constant(IC_IS_INSTANCE)), + SharkType::jint_type(), false))); + } +} + +void SharkTopLevelBlock::do_new() +{ + bool will_link; + ciInstanceKlass* klass = iter()->get_klass(will_link)->as_instance_klass(); + assert(will_link, "typeflow responsibility"); + + BasicBlock *tlab_alloc = NULL; + BasicBlock *got_tlab = NULL; + BasicBlock *heap_alloc = NULL; + BasicBlock *retry = NULL; + BasicBlock *got_heap = NULL; + BasicBlock *initialize = NULL; + BasicBlock *got_fast = NULL; + BasicBlock *slow_alloc_and_init = NULL; + BasicBlock *got_slow = NULL; + BasicBlock *push_object = NULL; + + SharkState *fast_state = NULL; + + Value *tlab_object = NULL; + Value *heap_object = NULL; + Value *fast_object = NULL; + Value *slow_object = NULL; + Value *object = NULL; + + SharkConstantPool constants(this); + + // The fast path + if (!Klass::layout_helper_needs_slow_path(klass->layout_helper())) { + if (UseTLAB) { + tlab_alloc = function()->CreateBlock("tlab_alloc"); + got_tlab = function()->CreateBlock("got_tlab"); + } + heap_alloc = function()->CreateBlock("heap_alloc"); + retry = function()->CreateBlock("retry"); + got_heap = function()->CreateBlock("got_heap"); + initialize = function()->CreateBlock("initialize"); + slow_alloc_and_init = function()->CreateBlock("slow_alloc_and_init"); + push_object = function()->CreateBlock("push_object"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ( + constants.tag_at(iter()->get_klass_index()), + LLVMValue::jbyte_constant(JVM_CONSTANT_Class)), + UseTLAB ? tlab_alloc : heap_alloc, slow_alloc_and_init); + + size_t size_in_bytes = klass->size_helper() << LogHeapWordSize; + + // Thread local allocation + if (UseTLAB) { + builder()->SetInsertPoint(tlab_alloc); + + Value *top_addr = builder()->CreateAddressOfStructEntry( + thread(), Thread::tlab_top_offset(), + PointerType::getUnqual(SharkType::intptr_type()), + "top_addr"); + + Value *end = builder()->CreateValueOfStructEntry( + thread(), Thread::tlab_end_offset(), + SharkType::intptr_type(), + "end"); + + Value *old_top = builder()->CreateLoad(top_addr, "old_top"); + Value *new_top = builder()->CreateAdd( + old_top, LLVMValue::intptr_constant(size_in_bytes)); + + builder()->CreateCondBr( + builder()->CreateICmpULE(new_top, end), + got_tlab, heap_alloc); + + builder()->SetInsertPoint(got_tlab); + tlab_object = builder()->CreateIntToPtr( + old_top, SharkType::jobject_type(), "tlab_object"); + + builder()->CreateStore(new_top, top_addr); + builder()->CreateBr(initialize); + } + + // Heap allocation + builder()->SetInsertPoint(heap_alloc); + + Value *top_addr = builder()->CreateIntToPtr( + builder()->pointer_constant(Universe::heap()->top_addr()), + PointerType::getUnqual(SharkType::intptr_type()), + "top_addr"); + + Value *end = builder()->CreateLoad( + builder()->CreateIntToPtr( + builder()->pointer_constant(Universe::heap()->end_addr()), + PointerType::getUnqual(SharkType::intptr_type())), + "end"); + + builder()->CreateBr(retry); + builder()->SetInsertPoint(retry); + + Value *old_top = builder()->CreateLoad(top_addr, "top"); + Value *new_top = builder()->CreateAdd( + old_top, LLVMValue::intptr_constant(size_in_bytes)); + + builder()->CreateCondBr( + builder()->CreateICmpULE(new_top, end), + got_heap, slow_alloc_and_init); + + builder()->SetInsertPoint(got_heap); + heap_object = builder()->CreateIntToPtr( + old_top, SharkType::jobject_type(), "heap_object"); + + Value *check = builder()->CreateCmpxchgPtr(new_top, top_addr, old_top); + builder()->CreateCondBr( + builder()->CreateICmpEQ(old_top, check), + initialize, retry); + + // Initialize the object + builder()->SetInsertPoint(initialize); + if (tlab_object) { + PHINode *phi = builder()->CreatePHI( + SharkType::jobject_type(), "fast_object"); + phi->addIncoming(tlab_object, got_tlab); + phi->addIncoming(heap_object, got_heap); + fast_object = phi; + } + else { + fast_object = heap_object; + } + + builder()->CreateMemset( + builder()->CreateBitCast( + fast_object, PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jbyte_constant(0), + LLVMValue::jint_constant(size_in_bytes), + LLVMValue::jint_constant(HeapWordSize)); + + Value *mark_addr = builder()->CreateAddressOfStructEntry( + fast_object, in_ByteSize(oopDesc::mark_offset_in_bytes()), + PointerType::getUnqual(SharkType::intptr_type()), + "mark_addr"); + + Value *klass_addr = builder()->CreateAddressOfStructEntry( + fast_object, in_ByteSize(oopDesc::klass_offset_in_bytes()), + PointerType::getUnqual(SharkType::jobject_type()), + "klass_addr"); + + // Set the mark + intptr_t mark; + if (UseBiasedLocking) { + Unimplemented(); + } + else { + mark = (intptr_t) markOopDesc::prototype(); + } + builder()->CreateStore(LLVMValue::intptr_constant(mark), mark_addr); + + // Set the class + Value *rtklass = constants.object_at(iter()->get_klass_index()); + builder()->CreateStore(rtklass, klass_addr); + got_fast = builder()->GetInsertBlock(); + + builder()->CreateBr(push_object); + builder()->SetInsertPoint(slow_alloc_and_init); + fast_state = current_state()->copy(); + } + + // The slow path + call_vm( + SharkRuntime::new_instance(), + LLVMValue::jint_constant(iter()->get_klass_index())); + slow_object = function()->CreateGetVMResult(); + got_slow = builder()->GetInsertBlock(); + + // Push the object + if (push_object) { + builder()->CreateBr(push_object); + builder()->SetInsertPoint(push_object); + } + if (fast_object) { + PHINode *phi = builder()->CreatePHI(SharkType::jobject_type(), "object"); + phi->addIncoming(fast_object, got_fast); + phi->addIncoming(slow_object, got_slow); + object = phi; + current_state()->merge(fast_state, got_fast, got_slow); + } + else { + object = slow_object; + } + + SharkValue *result = SharkValue::create_jobject(object); + result->set_zero_checked(true); + push(result); +} + +void SharkTopLevelBlock::do_newarray() +{ + BasicType type = (BasicType) iter()->get_index(); + + call_vm( + SharkRuntime::newarray(), + LLVMValue::jint_constant(type), + pop()->jint_value()); + + SharkValue *result = SharkValue::create_generic( + ciArrayKlass::make(ciType::make(type)), + function()->CreateGetVMResult()); + result->set_zero_checked(true); + push(result); +} + +void SharkTopLevelBlock::do_anewarray() +{ + bool will_link; + ciKlass *klass = iter()->get_klass(will_link); + assert(will_link, "typeflow responsibility"); + + ciObjArrayKlass *array_klass = ciObjArrayKlass::make(klass); + if (!array_klass->is_loaded()) { + Unimplemented(); + } + + call_vm( + SharkRuntime::anewarray(), + LLVMValue::jint_constant(iter()->get_klass_index()), + pop()->jint_value()); + + SharkValue *result = SharkValue::create_generic( + array_klass, function()->CreateGetVMResult()); + result->set_zero_checked(true); + push(result); +} + +void SharkTopLevelBlock::do_multianewarray() +{ + bool will_link; + ciArrayKlass *array_klass = iter()->get_klass(will_link)->as_array_klass(); + assert(will_link, "typeflow responsibility"); + + // The dimensions are stack values, so we use their slots for the + // dimensions array. Note that we are storing them in the reverse + // of normal stack order. + int ndims = iter()->get_dimensions(); + + Value *dimensions = function()->CreateAddressOfFrameEntry( + function()->stack_slots_offset() + max_stack() - xstack_depth(), + ArrayType::get(SharkType::jint_type(), ndims), + "dimensions"); + + for (int i = 0; i < ndims; i++) { + builder()->CreateStore( + xstack(ndims - 1 - i)->jint_value(), + builder()->CreateStructGEP(dimensions, i)); + } + + call_vm( + SharkRuntime::multianewarray(), + LLVMValue::jint_constant(iter()->get_klass_index()), + LLVMValue::jint_constant(ndims), + builder()->CreateStructGEP(dimensions, 0)); + + // Now we can pop the dimensions off the stack + for (int i = 0; i < ndims; i++) + pop(); + + SharkValue *result = SharkValue::create_generic( + array_klass, function()->CreateGetVMResult()); + result->set_zero_checked(true); + push(result); +} + +void SharkTopLevelBlock::do_monitorenter() +{ + SharkValue *lockee = pop(); + check_null(lockee); + Value *object = lockee->jobject_value(); + + // Find a free monitor, or one already allocated for this object + BasicBlock *loop_top = function()->CreateBlock("loop_top"); + BasicBlock *loop_iter = function()->CreateBlock("loop_iter"); + BasicBlock *loop_check = function()->CreateBlock("loop_check"); + BasicBlock *no_monitor = function()->CreateBlock("no_monitor"); + BasicBlock *got_monitor = function()->CreateBlock("got_monitor"); + + BasicBlock *entry_block = builder()->GetInsertBlock(); + builder()->CreateBr(loop_check); + + builder()->SetInsertPoint(loop_check); + PHINode *index = builder()->CreatePHI(SharkType::jint_type(), "index"); + index->addIncoming( + LLVMValue::jint_constant(function()->monitor_count() - 1), entry_block); + builder()->CreateCondBr( + builder()->CreateICmpUGE(index, LLVMValue::jint_constant(0)), + loop_top, no_monitor); + + builder()->SetInsertPoint(loop_top); + SharkMonitor* monitor = function()->monitor(index); + Value *smo = monitor->object(); + builder()->CreateCondBr( + builder()->CreateOr( + builder()->CreateICmpEQ(smo, LLVMValue::null()), + builder()->CreateICmpEQ(smo, object)), + got_monitor, loop_iter); + + builder()->SetInsertPoint(loop_iter); + index->addIncoming( + builder()->CreateSub(index, LLVMValue::jint_constant(1)), loop_iter); + builder()->CreateBr(loop_check); + + builder()->SetInsertPoint(no_monitor); + builder()->CreateShouldNotReachHere(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + // Acquire the lock + builder()->SetInsertPoint(got_monitor); + monitor->acquire(this, object); + check_pending_exception(); +} + +void SharkTopLevelBlock::do_monitorexit() +{ + SharkValue *lockee = pop(); + // The monitorexit can't throw an NPE because the verifier checks + // that the monitor operations are block structured before we + // compile. + // check_null(lockee); + Value *object = lockee->jobject_value(); + + // Find the monitor associated with this object + BasicBlock *loop_top = function()->CreateBlock("loop_top"); + BasicBlock *loop_iter = function()->CreateBlock("loop_iter"); + BasicBlock *loop_check = function()->CreateBlock("loop_check"); + BasicBlock *no_monitor = function()->CreateBlock("no_monitor"); + BasicBlock *got_monitor = function()->CreateBlock("got_monitor"); + + BasicBlock *entry_block = builder()->GetInsertBlock(); + builder()->CreateBr(loop_check); + + builder()->SetInsertPoint(loop_check); + PHINode *index = builder()->CreatePHI(SharkType::jint_type(), "index"); + index->addIncoming( + LLVMValue::jint_constant(function()->monitor_count() - 1), entry_block); + builder()->CreateCondBr( + builder()->CreateICmpUGE(index, LLVMValue::jint_constant(0)), + loop_top, no_monitor); + + builder()->SetInsertPoint(loop_top); + SharkMonitor* monitor = function()->monitor(index); + Value *smo = monitor->object(); + builder()->CreateCondBr( + builder()->CreateICmpEQ(smo, object), + got_monitor, loop_iter); + + builder()->SetInsertPoint(loop_iter); + index->addIncoming( + builder()->CreateSub(index, LLVMValue::jint_constant(1)), loop_iter); + builder()->CreateBr(loop_check); + + builder()->SetInsertPoint(no_monitor); + builder()->CreateShouldNotReachHere(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + // Release the lock + builder()->SetInsertPoint(got_monitor); + monitor->release(this); + // The monitorexit can't throw an NPE because the verifier checks + // that the monitor operations are block structured before we + // compile. + // check_pending_exception(); +} diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -0,0 +1,344 @@ +/* + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class SharkTopLevelBlock : public SharkBlock { + public: + SharkTopLevelBlock(SharkFunction* function, ciTypeFlow::Block* ciblock) + : SharkBlock(function->builder(), function->target(), function->iter()), + _function(function), + _ciblock(ciblock), + _entered(false), + _needs_phis(false), + _entry_state(NULL), + _entry_block(NULL) {} + + private: + SharkFunction* _function; + ciTypeFlow::Block* _ciblock; + + public: + SharkFunction* function() const + { + return _function; + } + ciTypeFlow::Block* ciblock() const + { + return _ciblock; + } + + public: + llvm::Value* thread() const + { + return function()->thread(); + } + + // Typeflow properties + public: + int index() const + { + return ciblock()->pre_order(); + } + bool has_trap() const + { + return ciblock()->has_trap(); + } + int trap_index() const + { + return ciblock()->trap_index(); + } + bool is_private_copy() const + { + return ciblock()->is_backedge_copy(); + } + int stack_depth_at_entry() const + { + return ciblock()->stack_size(); + } + ciType* local_type_at_entry(int index) const + { + return ciblock()->local_type_at(index); + } + ciType* stack_type_at_entry(int slot) const + { + return ciblock()->stack_type_at(slot); + } + int start() const + { + return ciblock()->start(); + } + int limit() const + { + return ciblock()->limit(); + } + bool falls_through() const + { + return ciblock()->control() == ciBlock::fall_through_bci; + } + int num_exceptions() const + { + return ciblock()->exceptions()->length(); + } + SharkTopLevelBlock* exception(int index) const + { + return function()->block(ciblock()->exceptions()->at(index)->pre_order()); + } + int num_successors() const + { + return ciblock()->successors()->length(); + } + SharkTopLevelBlock* successor(int index) const + { + return function()->block(ciblock()->successors()->at(index)->pre_order()); + } + SharkTopLevelBlock* bci_successor(int bci) const; + + // Entry state + private: + bool _entered; + bool _needs_phis; + + public: + bool entered() const + { + return _entered; + } + bool needs_phis() const + { + return _needs_phis; + } + + private: + void enter(SharkTopLevelBlock* predecessor, bool is_exception); + + public: + void enter() + { + enter(NULL, false); + } + + private: + SharkState* _entry_state; + + private: + SharkState* entry_state(); + + private: + llvm::BasicBlock* _entry_block; + + public: + llvm::BasicBlock* entry_block() const + { + return _entry_block; + } + + public: + void initialize(); + + public: + void add_incoming(SharkState* incoming_state); + + // Method + public: + llvm::Value* method() + { + return current_state()->method(); + } + + // Code generation + public: + void emit_IR(); + + // Helpers + private: + void do_zero_check(SharkValue* value); + llvm::Value* lookup_for_ldc(); + llvm::Value* lookup_for_field_access(); + + // VM calls + private: + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value** args_start, + llvm::Value** args_end) + { + current_state()->decache_for_VM_call(); + function()->set_last_Java_frame(); + llvm::CallInst *res = builder()->CreateCall(callee, args_start, args_end); + function()->reset_last_Java_frame(); + current_state()->cache_after_VM_call(); + return res; + } + + llvm::CallInst* call_vm(llvm::Constant* callee, + llvm::Value** args_start, + llvm::Value** args_end) + { + llvm::CallInst* res = call_vm_nocheck(callee, args_start, args_end); + check_pending_exception(); + return res; + } + + public: + llvm::CallInst* call_vm(llvm::Constant* callee) + { + llvm::Value *args[] = {thread()}; + return call_vm(callee, args, args + 1); + } + llvm::CallInst* call_vm(llvm::Constant* callee, + llvm::Value* arg1) + { + llvm::Value *args[] = {thread(), arg1}; + return call_vm(callee, args, args + 2); + } + llvm::CallInst* call_vm(llvm::Constant* callee, + llvm::Value* arg1, + llvm::Value* arg2) + { + llvm::Value *args[] = {thread(), arg1, arg2}; + return call_vm(callee, args, args + 3); + } + llvm::CallInst* call_vm(llvm::Constant* callee, + llvm::Value* arg1, + llvm::Value* arg2, + llvm::Value* arg3) + { + llvm::Value *args[] = {thread(), arg1, arg2, arg3}; + return call_vm(callee, args, args + 4); + } + + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee) + { + llvm::Value *args[] = {thread()}; + return call_vm_nocheck(callee, args, args + 1); + } + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value* arg1) + { + llvm::Value *args[] = {thread(), arg1}; + return call_vm_nocheck(callee, args, args + 2); + } + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value* arg1, + llvm::Value* arg2) + { + llvm::Value *args[] = {thread(), arg1, arg2}; + return call_vm_nocheck(callee, args, args + 3); + } + llvm::CallInst* call_vm_nocheck(llvm::Constant* callee, + llvm::Value* arg1, + llvm::Value* arg2, + llvm::Value* arg3) + { + llvm::Value *args[] = {thread(), arg1, arg2, arg3}; + return call_vm_nocheck(callee, args, args + 4); + } + + // Whole-method synchronization + public: + void acquire_method_lock(); + void release_method_lock(); + + // Error checking + private: + void check_bounds(SharkValue* array, SharkValue* index); + void check_pending_exception(bool attempt_catch = true); + void handle_exception(llvm::Value* exception, bool attempt_catch = true); + + // Safepoints + private: + void add_safepoint(); + + // Returns + private: + void call_register_finalizer(llvm::Value* receiver); + void handle_return(BasicType type, llvm::Value* exception); + void release_locked_monitors(); + + // arraylength + private: + void do_arraylength(); + + // *aload and *astore + private: + void do_aload(BasicType basic_type); + void do_astore(BasicType basic_type); + + // *return and athrow + private: + void do_return(BasicType type); + void do_athrow(); + + // goto* + private: + void do_goto(); + + // jsr* and ret + private: + void do_jsr(); + void do_ret(); + + // if* + private: + void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); + + // tableswitch and lookupswitch + private: + void do_switch(); + + // invoke* + private: + enum CallType { + CALL_DIRECT, + CALL_VIRTUAL, + CALL_INTERFACE + }; + CallType get_call_type(ciMethod* method); + llvm::Value* get_callee(CallType call_type, + ciMethod* method, + SharkValue* receiver); + + llvm::Value* get_direct_callee(ciMethod* method); + llvm::Value* get_virtual_callee(SharkValue* receiver, ciMethod* method); + + llvm::Value* get_virtual_callee(llvm::Value* cache, SharkValue* receiver); + llvm::Value* get_interface_callee(SharkValue* receiver); + + void do_call(); + + // checkcast and instanceof + private: + void do_instance_check(); + + // new and *newarray + private: + void do_new(); + void do_newarray(); + void do_anewarray(); + void do_multianewarray(); + + // monitorenter and monitorexit + private: + void do_monitorenter(); + void do_monitorexit(); +}; diff -r 22425c2ed9a9 -r b593d3ef9dce ports/hotspot/src/share/vm/shark/shark_globals.hpp --- a/ports/hotspot/src/share/vm/shark/shark_globals.hpp Wed Mar 04 11:01:54 2009 +0100 +++ b/ports/hotspot/src/share/vm/shark/shark_globals.hpp Wed Mar 04 10:41:13 2009 -0500 @@ -32,6 +32,10 @@ product(intx, MaxNodeLimit, 65000, \ "Maximum number of nodes") \ \ + /* inlining */ \ + product(intx, SharkMaxInlineSize, 32, \ + "Maximum bytecode size of methods to inline when using Shark") \ + \ /* compiler debugging */ \ develop(uintx, SharkStartAt, 0, \ "First method to consider when using Shark") \ @@ -48,8 +52,8 @@ develop(ccstr, SharkPrintBitcodeOf, NULL, \ "Print the LLVM bitcode of the specified method") \ \ - develop(ccstr, SharkPrintAsmOf, NULL, \ - "Print the asm of the specified method") \ + develop(ccstr, SharkPrintAsmOf, NULL, \ + "Print the asm of the specified method") \ \ develop(bool, SharkTraceBytecodes, false, \ "Trace bytecode compilation") \