//-----------------------------profile_receiver_type--------------------------- void Parse::profile_receiver_type(Node* receiver) { assert(method_data_update(), "must be generating profile code"); ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); assert(data->is_ReceiverTypeData(), "need ReceiverTypeData here"); // Skip if we aren't tracking receivers if (TypeProfileWidth < 1) { increment_md_counter_at(md, data, CounterData::count_offset()); return; } ciReceiverTypeData* rdata = (ciReceiverTypeData*)data->as_ReceiverTypeData(); Node* method_data = method_data_addressing(md, rdata, in_ByteSize(0)); // Using an adr_type of TypePtr::BOTTOM to work around anti-dep problems. // A better solution might be to use TypeRawPtr::BOTTOM with RC_NARROW_MEM. make_runtime_call(RC_LEAF, OptoRuntime::profile_receiver_type_Type(), CAST_FROM_FN_PTR(address, OptoRuntime::profile_receiver_type_C), "profile_receiver_type_C", TypePtr::BOTTOM, method_data, receiver); }
//------------------------------make_dtrace_method_entry_exit ---------------- // Dtrace -- record entry or exit of a method if compiled with dtrace support void GraphKit::make_dtrace_method_entry_exit(ciMethod* method, bool is_entry) { const TypeFunc *call_type = OptoRuntime::dtrace_method_entry_exit_Type(); address call_address = is_entry ? CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry) : CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit); const char *call_name = is_entry ? "dtrace_method_entry" : "dtrace_method_exit"; // Get base of thread-local storage area Node* thread = _gvn.transform( new (C) ThreadLocalNode() ); // Get method const TypePtr* method_type = TypeMetadataPtr::make(method); Node *method_node = _gvn.transform( ConNode::make(C, method_type) ); kill_dead_locals(); // For some reason, this call reads only raw memory. const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; make_runtime_call(RC_LEAF | RC_NARROW_MEM, call_type, call_address, call_name, raw_adr_type, thread, method_node); }
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. }
//----------------------------catch_inline_exceptions-------------------------- // Handle all exceptions thrown by an inlined method or individual bytecode. // Common case 1: we have no handler, so all exceptions merge right into // the rethrow case. // Case 2: we have some handlers, with loaded exception klasses that have // no subklasses. We do a Deutsch-Shiffman style type-check on the incoming // exception oop and branch to the handler directly. // Case 3: We have some handlers with subklasses or are not loaded at // compile-time. We have to call the runtime to resolve the exception. // So we insert a RethrowCall and all the logic that goes with it. void Parse::catch_inline_exceptions(SafePointNode* ex_map) { // Caller is responsible for saving away the map for normal control flow! assert(stopped(), "call set_map(NULL) first"); assert(method()->has_exception_handlers(), "don't come here w/o work to do"); Node* ex_node = saved_ex_oop(ex_map); if (ex_node == top()) { // No action needed. return; } const TypeInstPtr*ex_type=_gvn.type(ex_node)->is_instptr(); // determine potential exception handlers ciExceptionHandlerStream handlers(method(), bci(), ex_type->klass()->as_instance_klass(), ex_type->klass_is_exact()); // Start executing from the given throw state. (Keep its stack, for now.) // Get the exception oop as known at compile time. ex_node = use_exception_state(ex_map); // Get the exception oop klass from its header const TypeOopPtr *toop = ex_node->bottom_type()->is_oopptr(); const TypeKlassPtr *tkid = TypeKlassPtr::make_kid(toop->klass(),toop->klass_is_exact()); Node*ex_kid_node=_gvn.transform(new(C,2)GetKIDNode(control(),ex_node,tkid)); // Have handlers and the exception klass is not exact? It might be the // merging of many exact exception klasses (happens alot with nested inlined // throw/catch blocks). if (has_ex_handler() && !ex_type->klass_is_exact()) { // Compute the exception klass a little more cleverly. // Obvious solution is to simple do a GetKlass from the 'ex_node'. // However, if the ex_node is a PhiNode, I'm going to do a GetKlass for // each arm of the Phi. If I know something clever about the exceptions // I'm loading the class from, I can replace the GetKlass with the // klass constant for the exception oop. if( ex_node->is_Phi() ) { ex_kid_node=new(C,ex_node->req())PhiNode(ex_node->in(0),TypeKlassPtr::KID); for( uint i = 1; i < ex_node->req(); i++ ) { const TypeOopPtr *toopi = ex_node->in(i)->bottom_type()->is_oopptr(); const TypeKlassPtr *tkidi = TypeKlassPtr::make_kid(toop->klass(),toop->klass_is_exact()); Node *kid = _gvn.transform(new (C, 2) GetKIDNode(ex_node->in(0)->in(i), ex_node->in(i),tkidi)); ex_kid_node->init_req(i,kid); } _gvn.set_type(ex_kid_node,TypeKlassPtr::KID); } } // Scan the exception table for applicable handlers. // If none, we can call rethrow() and be done! // If precise (loaded with no subklasses), insert a D.S. style // pointer compare to the correct handler and loop back. // If imprecise, switch to the Rethrow VM-call style handling. int remaining = handlers.count_remaining(); // iterate through all entries sequentially ciInstanceKlass*handler_catch_klass=NULL; for (;!handlers.is_done(); handlers.next()) { // Do nothing if turned off if( !DeutschShiffmanExceptions ) break; ciExceptionHandler* handler = handlers.handler(); if (handler->is_rethrow()) { // If we fell off the end of the table without finding an imprecise // exception klass (and without finding a generic handler) then we // know this exception is not handled in this method. We just rethrow // the exception into the caller. throw_to_exit(make_exception_state(ex_node)); return; } // exception handler bci range covers throw_bci => investigate further int handler_bci = handler->handler_bci(); if (remaining == 1) { push_ex_oop(ex_node); // Push exception oop for handler merge_exception(handler_bci); // jump to handler return; // No more handling to be done here! } handler_catch_klass=handler->catch_klass(); if(!handler_catch_klass->is_loaded())//klass is not loaded? break; // Must call Rethrow! // Sharpen handler klass. Some klasses cannot have any oops // (e.g. interface with no implementations). const TypePtr* tpx = TypeOopPtr::make_from_klass_unique(handler_catch_klass); const TypeOopPtr *tp = tpx->isa_oopptr(); // Oop of this klass is possible? Node *handler_klass = tp ? _gvn.makecon( TypeKlassPtr::make_kid(tp->klass(),true) ) : NULL; Node *failure = gen_subtype_check( ex_kid_node, handler_klass, _gvn.type(ex_node) ); { PreserveJVMState pjvms(this); Node*ex_oop=_gvn.transform(new(C,2)CheckCastPPNode(control(),ex_node,tpx)); push_ex_oop(ex_oop); // Push exception oop for handler merge_exception(handler_bci); } // Come here if exception does not match handler. // Carry on with more handler checks. set_control(failure); --remaining; } assert(!stopped(), "you should return if you finish the chain"); if (remaining == 1) { // Further checks do not matter. } if (can_rerun_bytecode()) { // Do not push_ex_oop here! // Re-executing the bytecode will reproduce the throwing condition. bool must_throw = true; uncommon_trap(Deoptimization::Reason_unloaded,handler_catch_klass,"matching handler klass not loaded", must_throw); return; } // Oops, need to call into the VM to resolve the klasses at runtime. // Note: This call must not deoptimize, since it is not a real at this bci! kill_dead_locals(); make_runtime_call(RC_NO_LEAF | RC_MUST_THROW, false /* !must_callruntimenode */, OptoRuntime::forward_exception2_Type(), StubRoutines::forward_exception_entry2(), "forward_exception2", TypeRawPtr::BOTTOM, // sets the exception oop back into thr->_pending_ex ex_node); // Rethrow is a pure call, no side effects, only a result. // The result cannot be allocated, so we use I_O // Catch exceptions from the rethrow catch_call_exceptions(handlers); }