//============================================================================= void Parse::do_anewarray() { bool will_link; ciKlass* klass = iter().get_klass(will_link); // Uncommon Trap when class that array contains is not loaded // we need the loaded class for the rest of graph; do not // initialize the container class (see Java spec)!!! assert(will_link, "anewarray: typeflow responsibility"); ciObjArrayKlass* array_klass = ciObjArrayKlass::make(klass); // Check that array_klass object is loaded if (!array_klass->is_loaded()) { // Generate uncommon_trap for unloaded array_class uncommon_trap(Deoptimization::Reason_unloaded, Deoptimization::Action_reinterpret, array_klass); return; } kill_dead_locals(); const TypeKlassPtr* array_klass_type = TypeKlassPtr::make(array_klass); Node* count_val = pop(); Node* obj = new_array(makecon(array_klass_type), count_val, 1); push(obj); }
//------------------------------do_new----------------------------------------- void Parse::do_new() { kill_dead_locals(); bool will_link; ciInstanceKlass* klass = iter().get_klass(will_link)->as_instance_klass(); assert(will_link, "_new: typeflow responsibility"); // Should initialize, or throw an InstantiationError? if (!klass->is_initialized() && !klass->is_being_initialized() || klass->is_abstract() || klass->is_interface() || klass->name() == ciSymbol::java_lang_Class() || iter().is_unresolved_klass()) { uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_reinterpret, klass); return; } if (klass->is_being_initialized()) { emit_guard_for_new(klass); } Node* kls = makecon(TypeKlassPtr::make(klass)); Node* obj = new_instance(kls); // Push resultant oop onto stack push(obj); // Keep track of whether opportunities exist for StringBuilder // optimizations. if (OptimizeStringConcat && (klass == C->env()->StringBuilder_klass() || klass == C->env()->StringBuffer_klass())) { C->set_has_stringbuilder(true); } }
//------------------------------do_instanceof---------------------------------- void Parse::do_instanceof() { if (stopped()) return; // We would like to return false if class is not loaded, emitting a // dependency, but Java requires instanceof to load its operand. // Throw uncommon trap if class is not loaded bool will_link; ciKlass* klass = iter().get_klass(will_link); if (!will_link) { if (C->log() != NULL) { C->log()->elem("assert_null reason='instanceof' klass='%d'", C->log()->identify(klass)); } null_assert(peek()); assert( stopped() || _gvn.type(peek())->higher_equal(TypePtr::NULL_PTR), "what's left behind is null" ); if (!stopped()) { // The object is now known to be null. // Shortcut the effect of gen_instanceof and return "false" directly. pop(); // pop the null push(_gvn.intcon(0)); // push false answer } return; } // Push the bool result back on stack Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass))); // Pop from stack AFTER gen_instanceof because it can uncommon trap. pop(); push(res); }
void Parse::emit_guard_for_new(ciInstanceKlass* klass) { // Emit guarded new // if (klass->_init_thread != current_thread || // klass->_init_state != being_initialized) // uncommon_trap Node* cur_thread = _gvn.transform( new (C, 1) ThreadLocalNode() ); Node* merge = new (C, 3) RegionNode(3); _gvn.set_type(merge, Type::CONTROL); Node* kls = makecon(TypeKlassPtr::make(klass)); Node* init_thread_offset = _gvn.MakeConX(instanceKlass::init_thread_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()); Node* adr_node = basic_plus_adr(kls, kls, init_thread_offset); Node* init_thread = make_load(NULL, adr_node, TypeRawPtr::BOTTOM, T_ADDRESS); Node *tst = Bool( CmpP( init_thread, cur_thread), BoolTest::eq); IfNode* iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN); set_control(IfTrue(iff)); merge->set_req(1, IfFalse(iff)); Node* init_state_offset = _gvn.MakeConX(instanceKlass::init_state_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()); adr_node = basic_plus_adr(kls, kls, init_state_offset); Node* init_state = make_load(NULL, adr_node, TypeInt::INT, T_INT); Node* being_init = _gvn.intcon(instanceKlass::being_initialized); tst = Bool( CmpI( init_state, being_init), BoolTest::eq); iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN); set_control(IfTrue(iff)); merge->set_req(2, IfFalse(iff)); PreserveJVMState pjvms(this); record_for_igvn(merge); set_control(merge); uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_reinterpret, klass); }
void Parse::do_newarray(BasicType elem_type) { kill_dead_locals(); Node* count_val = pop(); const TypeKlassPtr* array_klass = TypeKlassPtr::make(ciTypeArrayKlass::make(elem_type)); Node* obj = new_array(makecon(array_klass), count_val, 1); // Push resultant oop onto stack push(obj); }
bool Parse::push_constant(ciConstant constant, bool require_constant) { switch (constant.basic_type()) { case T_BOOLEAN: push( intcon(constant.as_boolean()) ); break; case T_INT: push( intcon(constant.as_int()) ); break; case T_CHAR: push( intcon(constant.as_char()) ); break; case T_BYTE: push( intcon(constant.as_byte()) ); break; case T_SHORT: push( intcon(constant.as_short()) ); break; case T_FLOAT: push( makecon(TypeF::make(constant.as_float())) ); break; case T_DOUBLE: push_pair( makecon(TypeD::make(constant.as_double())) ); break; case T_LONG: push_pair( longcon(constant.as_long()) ); break; case T_ARRAY: case T_OBJECT: { // cases: // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0) // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2) // An oop is not scavengable if it is in the perm gen. ciObject* oop_constant = constant.as_object(); if (oop_constant->is_null_object()) { push( zerocon(T_OBJECT) ); break; } else if (require_constant || oop_constant->should_be_constant()) { push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) ); break; } else { // we cannot inline the oop, but we can use it later to narrow a type return false; } } case T_ILLEGAL: { // Invalid ciConstant returned due to OutOfMemoryError in the CI assert(C->env()->failing(), "otherwise should not see this"); // These always occur because of object types; we are going to // bail out anyway, so make the stack depths match up push( zerocon(T_OBJECT) ); return false; } default: ShouldNotReachHere(); return false; } // success return true; }
// Helper for byte_map_base Node* byte_map_base_node() { // Get base of card map CardTableModRefBS* ct = (CardTableModRefBS*)(Universe::heap()->barrier_set()); assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust users of this code"); if (ct->byte_map_base != NULL) { return makecon(TypeRawPtr::make((address)ct->byte_map_base)); } else { return null(); } }
//----------------------test_counter_against_threshold ------------------------ void Parse::test_counter_against_threshold(Node* cnt, int limit) { // Test the counter against the limit and uncommon trap if greater. // This code is largely copied from the range check code in // array_addressing() // Test invocation count vs threshold Node *threshold = makecon(TypeInt::make(limit)); Node *chk = _gvn.transform( new (C) CmpUNode( cnt, threshold) ); BoolTest::mask btest = BoolTest::lt; Node *tst = _gvn.transform( new (C) BoolNode( chk, btest) ); // Branch to failure if threshold exceeded { BuildCutout unless(this, tst, PROB_ALWAYS); uncommon_trap(Deoptimization::Reason_age, Deoptimization::Action_maybe_recompile); } }
//----------------------increment_and_test_invocation_counter------------------- void Parse::increment_and_test_invocation_counter(int limit) { if (!count_invocations()) return; // Get the Method* node. const TypePtr* adr_type = TypeMetadataPtr::make(method()); Node *method_node = makecon(adr_type); // Load the interpreter_invocation_counter from the Method*. int offset = Method::interpreter_invocation_counter_offset_in_bytes(); Node* adr_node = basic_plus_adr(method_node, method_node, offset); Node* cnt = make_load(NULL, adr_node, TypeInt::INT, T_INT, adr_type); test_counter_against_threshold(cnt, limit); // Add one to the counter and store Node* incr = _gvn.transform(new (C) AddINode(cnt, _gvn.intcon(1))); store_to_memory( NULL, adr_node, incr, T_INT, adr_type ); }
// Expand simple expressions like new int[3][5] and new Object[2][nonConLen]. // Also handle the degenerate 1-dimensional case of anewarray. Node* Parse::expand_multianewarray(ciArrayKlass* array_klass, Node* *lengths, int ndimensions, int nargs) { Node* length = lengths[0]; assert(length != NULL, ""); Node* array = new_array(makecon(TypeKlassPtr::make(array_klass)), length, nargs); if (ndimensions > 1) { jint length_con = find_int_con(length, -1); guarantee(length_con >= 0, "non-constant multianewarray"); ciArrayKlass* array_klass_1 = array_klass->as_obj_array_klass()->element_klass()->as_array_klass(); const TypePtr* adr_type = TypeAryPtr::OOPS; const TypeOopPtr* elemtype = _gvn.type(array)->is_aryptr()->elem()->make_oopptr(); const intptr_t header = arrayOopDesc::base_offset_in_bytes(T_OBJECT); for (jint i = 0; i < length_con; i++) { Node* elem = expand_multianewarray(array_klass_1, &lengths[1], ndimensions-1, nargs); intptr_t offset = header + ((intptr_t)i << LogBytesPerHeapOop); Node* eaddr = basic_plus_adr(array, offset); store_oop_to_array(control(), array, eaddr, adr_type, elem, elemtype, T_OBJECT); } } return array; }
//----------------------------method_data_addressing--------------------------- Node* Parse::method_data_addressing(ciMethodData* md, ciProfileData* data, ByteSize counter_offset, Node* idx, uint stride) { // Get offset within MethodData* of the data array ByteSize data_offset = MethodData::data_offset(); // Get cell offset of the ProfileData within data array int cell_offset = md->dp_to_di(data->dp()); // Add in counter_offset, the # of bytes into the ProfileData of counter or flag int offset = in_bytes(data_offset) + cell_offset + in_bytes(counter_offset); const TypePtr* adr_type = TypeMetadataPtr::make(md); Node* mdo = makecon(adr_type); Node* ptr = basic_plus_adr(mdo, mdo, offset); if (stride != 0) { Node* str = _gvn.MakeConX(stride); Node* scale = _gvn.transform( new (C) MulXNode( idx, str ) ); ptr = _gvn.transform( new (C) AddPNode( mdo, ptr, scale ) ); } return ptr; }
//============================================================================= //------------------------------do_checkcast----------------------------------- void Parse::do_checkcast() { bool will_link; ciKlass* klass = iter().get_klass(will_link); Node *obj = peek(); // Throw uncommon trap if class is not loaded or the value we are casting // _from_ is not loaded, and value is not null. If the value _is_ NULL, // then the checkcast does nothing. const TypeOopPtr *tp = _gvn.type(obj)->isa_oopptr(); if (!will_link || (tp && tp->klass() && !tp->klass()->is_loaded())) { if (C->log() != NULL) { if (!will_link) { C->log()->elem("assert_null reason='checkcast' klass='%d'", C->log()->identify(klass)); } if (tp && tp->klass() && !tp->klass()->is_loaded()) { // %%% Cannot happen? C->log()->elem("assert_null reason='checkcast source' klass='%d'", C->log()->identify(tp->klass())); } } null_assert(obj); assert( stopped() || _gvn.type(peek())->higher_equal(TypePtr::NULL_PTR), "what's left behind is null" ); if (!stopped()) { profile_null_checkcast(); } return; } Node *res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass)) ); // Pop from stack AFTER gen_checkcast because it can uncommon trap and // the debug info has to be correct. pop(); push(res); }
//----------------------increment_and_test_invocation_counter------------------- void Parse::increment_and_test_invocation_counter(int limit) { if (!count_invocations()) return; // Get the Method* node. ciMethod* m = method(); MethodCounters* counters_adr = m->ensure_method_counters(); if (counters_adr == NULL) { C->record_failure("method counters allocation failed"); return; } Node* ctrl = control(); const TypePtr* adr_type = TypeRawPtr::make((address) counters_adr); Node *counters_node = makecon(adr_type); Node* adr_iic_node = basic_plus_adr(counters_node, counters_node, MethodCounters::interpreter_invocation_counter_offset_in_bytes()); Node* cnt = make_load(ctrl, adr_iic_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered); test_counter_against_threshold(cnt, limit); // Add one to the counter and store Node* incr = _gvn.transform(new AddINode(cnt, _gvn.intcon(1))); store_to_memory(ctrl, adr_iic_node, incr, T_INT, adr_type, MemNode::unordered); }
//------------------------------array_store_check------------------------------ // pull array from stack and check that the store is valid void Parse::array_store_check() { // Shorthand access to array store elements without popping them. Node *obj = peek(0); Node *idx = peek(1); Node *ary = peek(2); if (_gvn.type(obj) == TypePtr::NULL_PTR) { // There's never a type check on null values. // This cutout lets us avoid the uncommon_trap(Reason_array_check) // below, which turns into a performance liability if the // gen_checkcast folds up completely. return; } // Extract the array klass type int klass_offset = oopDesc::klass_offset_in_bytes(); Node* p = basic_plus_adr( ary, ary, klass_offset ); // p's type is array-of-OOPS plus klass_offset Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) ); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); // array_klass's type is generally INexact array-of-oop. Heroically // cast the array klass to EXACT array and uncommon-trap if the cast // fails. bool always_see_exact_class = false; if (MonomorphicArrayCheck && !too_many_traps(Deoptimization::Reason_array_check)) { always_see_exact_class = true; // (If no MDO at all, hope for the best, until a trap actually occurs.) } // Is the array klass is exactly its defined type? if (always_see_exact_class && !tak->klass_is_exact()) { // Make a constant out of the inexact array klass const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr(); Node* con = makecon(extak); Node* cmp = _gvn.transform(new (C) CmpPNode( array_klass, con )); Node* bol = _gvn.transform(new (C) BoolNode( cmp, BoolTest::eq )); Node* ctrl= control(); { BuildCutout unless(this, bol, PROB_MAX); uncommon_trap(Deoptimization::Reason_array_check, Deoptimization::Action_maybe_recompile, tak->klass()); } if (stopped()) { // MUST uncommon-trap? set_control(ctrl); // Then Don't Do It, just fall into the normal checking } else { // Cast array klass to exactness: // Use the exact constant value we know it is. replace_in_map(array_klass,con); CompileLog* log = C->log(); if (log != NULL) { log->elem("cast_up reason='monomorphic_array' from='%d' to='(exact)'", log->identify(tak->klass())); } array_klass = con; // Use cast value moving forward } } // Come here for polymorphic array klasses // Extract the array element class int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) ); // Check (the hard way) and throw if not a subklass. // Result is ignored, we just need the CFG effects. gen_checkcast( obj, a_e_klass ); }
//--------------------gen_stub------------------------------- void GraphKit::gen_stub(address C_function, const char *name, int is_fancy_jump, bool pass_tls, bool return_pc) { ResourceMark rm; const TypeTuple *jdomain = C->tf()->domain(); const TypeTuple *jrange = C->tf()->range(); // The procedure start StartNode* start = new (C) StartNode(root(), jdomain); _gvn.set_type_bottom(start); // Make a map, with JVM state uint parm_cnt = jdomain->cnt(); uint max_map = MAX2(2*parm_cnt+1, jrange->cnt()); // %%% SynchronizationEntryBCI is redundant; use InvocationEntryBci in interfaces assert(SynchronizationEntryBCI == InvocationEntryBci, ""); JVMState* jvms = new (C) JVMState(0); jvms->set_bci(InvocationEntryBci); jvms->set_monoff(max_map); jvms->set_scloff(max_map); jvms->set_endoff(max_map); { SafePointNode *map = new (C) SafePointNode( max_map, jvms ); jvms->set_map(map); set_jvms(jvms); assert(map == this->map(), "kit.map is set"); } // Make up the parameters uint i; for( i = 0; i < parm_cnt; i++ ) map()->init_req(i, _gvn.transform(new (C) ParmNode(start, i))); for( ; i<map()->req(); i++ ) map()->init_req(i, top()); // For nicer debugging // GraphKit requires memory to be a MergeMemNode: set_all_memory(map()->memory()); // Get base of thread-local storage area Node* thread = _gvn.transform( new (C) ThreadLocalNode() ); const int NoAlias = Compile::AliasIdxBot; Node* adr_last_Java_pc = basic_plus_adr(top(), thread, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::last_Java_pc_offset())); #if defined(SPARC) Node* adr_flags = basic_plus_adr(top(), thread, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::flags_offset())); #endif /* defined(SPARC) */ // Drop in the last_Java_sp. last_Java_fp is not touched. // Always do this after the other "last_Java_frame" fields are set since // as soon as last_Java_sp != NULL the has_last_Java_frame is true and // users will look at the other fields. // Node *adr_sp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_sp_offset())); Node *last_sp = basic_plus_adr(top(), frameptr(), (intptr_t) STACK_BIAS); store_to_memory(NULL, adr_sp, last_sp, T_ADDRESS, NoAlias); // Set _thread_in_native // The order of stores into TLS is critical! Setting _thread_in_native MUST // be last, because a GC is allowed at any time after setting it and the GC // will require last_Java_pc and last_Java_sp. Node* adr_state = basic_plus_adr(top(), thread, in_bytes(JavaThread::thread_state_offset())); //----------------------------- // Compute signature for C call. Varies from the Java signature! const Type **fields = TypeTuple::fields(2*parm_cnt+2); uint cnt = TypeFunc::Parms; // The C routines gets the base of thread-local storage passed in as an // extra argument. Not all calls need it, but its cheap to add here. for( ; cnt<parm_cnt; cnt++ ) fields[cnt] = jdomain->field_at(cnt); fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage // Also pass in the caller's PC, if asked for. if( return_pc ) fields[cnt++] = TypeRawPtr::BOTTOM; // Return PC const TypeTuple* domain = TypeTuple::make(cnt,fields); // The C routine we are about to call cannot return an oop; it can block on // exit and a GC will trash the oop while it sits in C-land. Instead, we // return the oop through TLS for runtime calls. // Also, C routines returning integer subword values leave the high // order bits dirty; these must be cleaned up by explicit sign extension. const Type* retval = (jrange->cnt() == TypeFunc::Parms) ? Type::TOP : jrange->field_at(TypeFunc::Parms); // Make a private copy of jrange->fields(); const Type **rfields = TypeTuple::fields(jrange->cnt() - TypeFunc::Parms); // Fixup oop returns int retval_ptr = retval->isa_oop_ptr(); if( retval_ptr ) { assert( pass_tls, "Oop must be returned thru TLS" ); // Fancy-jumps return address; others return void rfields[TypeFunc::Parms] = is_fancy_jump ? TypeRawPtr::BOTTOM : Type::TOP; } else if( retval->isa_int() ) { // Returning any integer subtype? // "Fatten" byte, char & short return types to 'int' to show that // the native C code can return values with junk high order bits. // We'll sign-extend it below later. rfields[TypeFunc::Parms] = TypeInt::INT; // It's "dirty" and needs sign-ext } else if( jrange->cnt() >= TypeFunc::Parms+1 ) { // Else copy other types rfields[TypeFunc::Parms] = jrange->field_at(TypeFunc::Parms); if( jrange->cnt() == TypeFunc::Parms+2 ) rfields[TypeFunc::Parms+1] = jrange->field_at(TypeFunc::Parms+1); } const TypeTuple* range = TypeTuple::make(jrange->cnt(),rfields); // Final C signature const TypeFunc *c_sig = TypeFunc::make(domain,range); //----------------------------- // Make the call node CallRuntimeNode *call = new (C) CallRuntimeNode(c_sig, C_function, name, TypePtr::BOTTOM); //----------------------------- // Fix-up the debug info for the call call->set_jvms( new (C) JVMState(0) ); call->jvms()->set_bci(0); call->jvms()->set_offsets(cnt); // Set fixed predefined input arguments cnt = 0; for( i=0; i<TypeFunc::Parms; i++ ) call->init_req( cnt++, map()->in(i) ); // A little too aggressive on the parm copy; return address is not an input call->set_req(TypeFunc::ReturnAdr, top()); for( ; i<parm_cnt; i++ ) // Regular input arguments call->init_req( cnt++, map()->in(i) ); call->init_req( cnt++, thread ); if( return_pc ) // Return PC, if asked for call->init_req( cnt++, returnadr() ); _gvn.transform_no_reclaim(call); //----------------------------- // Now set up the return results set_control( _gvn.transform( new (C) ProjNode(call,TypeFunc::Control)) ); set_i_o( _gvn.transform( new (C) ProjNode(call,TypeFunc::I_O )) ); set_all_memory_call(call); if (range->cnt() > TypeFunc::Parms) { Node* retnode = _gvn.transform( new (C) ProjNode(call,TypeFunc::Parms) ); // C-land is allowed to return sub-word values. Convert to integer type. assert( retval != Type::TOP, "" ); if (retval == TypeInt::BOOL) { retnode = _gvn.transform( new (C) AndINode(retnode, intcon(0xFF)) ); } else if (retval == TypeInt::CHAR) { retnode = _gvn.transform( new (C) AndINode(retnode, intcon(0xFFFF)) ); } else if (retval == TypeInt::BYTE) { retnode = _gvn.transform( new (C) LShiftINode(retnode, intcon(24)) ); retnode = _gvn.transform( new (C) RShiftINode(retnode, intcon(24)) ); } else if (retval == TypeInt::SHORT) { retnode = _gvn.transform( new (C) LShiftINode(retnode, intcon(16)) ); retnode = _gvn.transform( new (C) RShiftINode(retnode, intcon(16)) ); } map()->set_req( TypeFunc::Parms, retnode ); } //----------------------------- // Clear last_Java_sp store_to_memory(NULL, adr_sp, null(), T_ADDRESS, NoAlias); // Clear last_Java_pc and (optionally)_flags store_to_memory(NULL, adr_last_Java_pc, null(), T_ADDRESS, NoAlias); #if defined(SPARC) store_to_memory(NULL, adr_flags, intcon(0), T_INT, NoAlias); #endif /* defined(SPARC) */ #ifdef IA64 Node* adr_last_Java_fp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_fp_offset())); if( os::is_MP() ) insert_mem_bar(Op_MemBarRelease); store_to_memory(NULL, adr_last_Java_fp, null(), T_ADDRESS, NoAlias); #endif // For is-fancy-jump, the C-return value is also the branch target Node* target = map()->in(TypeFunc::Parms); // Runtime call returning oop in TLS? Fetch it out if( pass_tls ) { Node* adr = basic_plus_adr(top(), thread, in_bytes(JavaThread::vm_result_offset())); Node* vm_result = make_load(NULL, adr, TypeOopPtr::BOTTOM, T_OBJECT, NoAlias, false); map()->set_req(TypeFunc::Parms, vm_result); // vm_result passed as result // clear thread-local-storage(tls) store_to_memory(NULL, adr, null(), T_ADDRESS, NoAlias); } //----------------------------- // check exception Node* adr = basic_plus_adr(top(), thread, in_bytes(Thread::pending_exception_offset())); Node* pending = make_load(NULL, adr, TypeOopPtr::BOTTOM, T_OBJECT, NoAlias, false); Node* exit_memory = reset_memory(); Node* cmp = _gvn.transform( new (C) CmpPNode(pending, null()) ); Node* bo = _gvn.transform( new (C) BoolNode(cmp, BoolTest::ne) ); IfNode *iff = create_and_map_if(control(), bo, PROB_MIN, COUNT_UNKNOWN); Node* if_null = _gvn.transform( new (C) IfFalseNode(iff) ); Node* if_not_null = _gvn.transform( new (C) IfTrueNode(iff) ); assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before"); Node *exc_target = makecon(TypeRawPtr::make( StubRoutines::forward_exception_entry() )); Node *to_exc = new (C) TailCallNode(if_not_null, i_o(), exit_memory, frameptr(), returnadr(), exc_target, null()); root()->add_req(_gvn.transform(to_exc)); // bind to root to keep live C->init_start(start); //----------------------------- // If this is a normal subroutine return, issue the return and be done. Node *ret; switch( is_fancy_jump ) { case 0: // Make a return instruction // Return to caller, free any space for return address ret = new (C) ReturnNode(TypeFunc::Parms, if_null, i_o(), exit_memory, frameptr(), returnadr()); if (C->tf()->range()->cnt() > TypeFunc::Parms) ret->add_req( map()->in(TypeFunc::Parms) ); break; case 1: // This is a fancy tail-call jump. Jump to computed address. // Jump to new callee; leave old return address alone. ret = new (C) TailCallNode(if_null, i_o(), exit_memory, frameptr(), returnadr(), target, map()->in(TypeFunc::Parms)); break; case 2: // Pop return address & jump // Throw away old return address; jump to new computed address //assert(C_function == CAST_FROM_FN_PTR(address, OptoRuntime::rethrow_C), "fancy_jump==2 only for rethrow"); ret = new (C) TailJumpNode(if_null, i_o(), exit_memory, frameptr(), target, map()->in(TypeFunc::Parms)); break; default: ShouldNotReachHere(); } root()->add_req(_gvn.transform(ret)); }
void Parse::do_multianewarray() { int ndimensions = iter().get_dimensions(); // the m-dimensional array bool will_link; ciArrayKlass* array_klass = iter().get_klass(will_link)->as_array_klass(); assert(will_link, "multianewarray: typeflow responsibility"); // Note: Array classes are always initialized; no is_initialized check. enum { MAX_DIMENSION = 5 }; if (ndimensions > MAX_DIMENSION || ndimensions <= 0) { uncommon_trap(Deoptimization::Reason_unhandled, Deoptimization::Action_none); return; } kill_dead_locals(); // get the lengths from the stack (first dimension is on top) Node* length[MAX_DIMENSION+1]; length[ndimensions] = NULL; // terminating null for make_runtime_call int j; for (j = ndimensions-1; j >= 0 ; j--) length[j] = pop(); // The original expression was of this form: new T[length0][length1]... // It is often the case that the lengths are small (except the last). // If that happens, use the fast 1-d creator a constant number of times. const jint expand_limit = MIN2((juint)MultiArrayExpandLimit, (juint)100); jint expand_count = 1; // count of allocations in the expansion jint expand_fanout = 1; // running total fanout for (j = 0; j < ndimensions-1; j++) { jint dim_con = find_int_con(length[j], -1); expand_fanout *= dim_con; expand_count += expand_fanout; // count the level-J sub-arrays if (dim_con <= 0 || dim_con > expand_limit || expand_count > expand_limit) { expand_count = 0; break; } } // Can use multianewarray instead of [a]newarray if only one dimension, // or if all non-final dimensions are small constants. if (ndimensions == 1 || (1 <= expand_count && expand_count <= expand_limit)) { Node* obj = NULL; // Set the original stack and the reexecute bit for the interpreter // to reexecute the multianewarray bytecode if deoptimization happens. // Do it unconditionally even for one dimension multianewarray. // Note: the reexecute bit will be set in GraphKit::add_safepoint_edges() // when AllocateArray node for newarray is created. { PreserveReexecuteState preexecs(this); _sp += ndimensions; // Pass 0 as nargs since uncommon trap code does not need to restore stack. obj = expand_multianewarray(array_klass, &length[0], ndimensions, 0); } //original reexecute and sp are set back here push(obj); return; } address fun = NULL; switch (ndimensions) { //case 1: Actually, there is no case 1. It's handled by new_array. case 2: fun = OptoRuntime::multianewarray2_Java(); break; case 3: fun = OptoRuntime::multianewarray3_Java(); break; case 4: fun = OptoRuntime::multianewarray4_Java(); break; case 5: fun = OptoRuntime::multianewarray5_Java(); break; default: ShouldNotReachHere(); }; Node* c = make_runtime_call(RC_NO_LEAF | RC_NO_IO, OptoRuntime::multianewarray_Type(ndimensions), fun, NULL, TypeRawPtr::BOTTOM, makecon(TypeKlassPtr::make(array_klass)), length[0], length[1], length[2], length[3], length[4]); Node* res = _gvn.transform(new (C, 1) ProjNode(c, TypeFunc::Parms)); const Type* type = TypeOopPtr::make_from_klass_raw(array_klass); // Improve the type: We know it's not null, exact, and of a given length. type = type->is_ptr()->cast_to_ptr_type(TypePtr::NotNull); type = type->is_aryptr()->cast_to_exactness(true); const TypeInt* ltype = _gvn.find_int_type(length[0]); if (ltype != NULL) type = type->is_aryptr()->cast_to_size(ltype); // We cannot sharpen the nested sub-arrays, since the top level is mutable. Node* cast = _gvn.transform( new (C, 2) CheckCastPPNode(control(), res, type) ); push(cast); // Possible improvements: // - Make a fast path for small multi-arrays. (W/ implicit init. loops.) // - Issue CastII against length[*] values, to TypeInt::POS. }
//------------------------------array_store_check------------------------------ // pull array from stack and check that the store is valid void Parse::array_store_check() { // Shorthand access to array store elements without popping them. Node *obj = peek(0); Node *idx = peek(1); Node *ary = peek(2); if (_gvn.type(obj) == TypePtr::NULL_PTR) { // There's never a type check on null values. // This cutout lets us avoid the uncommon_trap(Reason_array_check) // below, which turns into a performance liability if the // gen_checkcast folds up completely. return; } // Extract the array klass type int klass_offset = oopDesc::klass_offset_in_bytes(); Node* p = basic_plus_adr( ary, ary, klass_offset ); // p's type is array-of-OOPS plus klass_offset Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS)); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); // The type of array_klass is usually INexact array-of-oop. Heroically // cast array_klass to EXACT array and uncommon-trap if the cast fails. // Make constant out of the inexact array klass, but use it only if the cast // succeeds. bool always_see_exact_class = false; if (MonomorphicArrayCheck && !too_many_traps(Deoptimization::Reason_array_check) && !tak->klass_is_exact() && tak != TypeKlassPtr::OBJECT) { // Regarding the fourth condition in the if-statement from above: // // If the compiler has determined that the type of array 'ary' (represented // by 'array_klass') is java/lang/Object, the compiler must not assume that // the array 'ary' is monomorphic. // // If 'ary' were of type java/lang/Object, this arraystore would have to fail, // because it is not possible to perform a arraystore into an object that is not // a "proper" array. // // Therefore, let's obtain at runtime the type of 'ary' and check if we can still // successfully perform the store. // // The implementation reasons for the condition are the following: // // java/lang/Object is the superclass of all arrays, but it is represented by the VM // as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect // 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses. // // See issue JDK-8057622 for details. always_see_exact_class = true; // (If no MDO at all, hope for the best, until a trap actually occurs.) // Make a constant out of the inexact array klass const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr(); Node* con = makecon(extak); Node* cmp = _gvn.transform(new CmpPNode( array_klass, con )); Node* bol = _gvn.transform(new BoolNode( cmp, BoolTest::eq )); Node* ctrl= control(); { BuildCutout unless(this, bol, PROB_MAX); uncommon_trap(Deoptimization::Reason_array_check, Deoptimization::Action_maybe_recompile, tak->klass()); } if (stopped()) { // MUST uncommon-trap? set_control(ctrl); // Then Don't Do It, just fall into the normal checking } else { // Cast array klass to exactness: // Use the exact constant value we know it is. replace_in_map(array_klass,con); CompileLog* log = C->log(); if (log != NULL) { log->elem("cast_up reason='monomorphic_array' from='%d' to='(exact)'", log->identify(tak->klass())); } array_klass = con; // Use cast value moving forward } } // Come here for polymorphic array klasses // Extract the array element class int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true, // we must set a control edge from the IfTrue node created by the uncommon_trap above to the // LoadKlassNode. Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL, immutable_memory(), p2, tak)); // Check (the hard way) and throw if not a subklass. // Result is ignored, we just need the CFG effects. gen_checkcast(obj, a_e_klass); }