void Parse::do_field_access(bool is_get, bool is_field) { bool will_link; ciField* field = iter().get_field(will_link); assert(will_link, "getfield: typeflow responsibility"); ciInstanceKlass* field_holder = field->holder(); if (is_field == field->is_static()) { // Interpreter will throw java_lang_IncompatibleClassChangeError // Check this before allowing <clinit> methods to access static fields uncommon_trap(Deoptimization::Reason_unhandled, Deoptimization::Action_none); return; } if (!is_field && !field_holder->is_initialized()) { if (!static_field_ok_in_clinit(field, method())) { uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_reinterpret, NULL, "!static_field_ok_in_clinit"); return; } } assert(field->will_link(method()->holder(), bc()), "getfield: typeflow responsibility"); // Note: We do not check for an unloaded field type here any more. // Generate code for the object pointer. Node* obj; if (is_field) { int obj_depth = is_get ? 0 : field->type()->size(); obj = do_null_check(peek(obj_depth), T_OBJECT); // Compile-time detect of null-exception? if (stopped()) return; #ifdef ASSERT const TypeInstPtr *tjp = TypeInstPtr::make(TypePtr::NotNull, iter().get_declared_field_holder()); assert(_gvn.type(obj)->higher_equal(tjp), "cast_up is no longer needed"); #endif if (is_get) { --_sp; // pop receiver before getting do_get_xxx(obj, field, is_field); } else { do_put_xxx(obj, field, is_field); --_sp; // pop receiver after putting } } else { const TypeInstPtr* tip = TypeInstPtr::make(field_holder->java_mirror()); obj = _gvn.makecon(tip); if (is_get) { do_get_xxx(obj, field, is_field); } else { do_put_xxx(obj, field, is_field); } } }
// Do a null check on the receiver, which is in argument(0). Node* null_check_receiver(ciMethod* callee) { assert(!callee->is_static(), "must be a virtual method"); int nargs = 1 + callee->signature()->size(); // Null check on self without removing any arguments. The argument // null check technically happens in the wrong place, which can lead to // invalid stack traces when the primitive is inlined into a method // which handles NullPointerExceptions. Node* receiver = argument(0); _sp += nargs; receiver = do_null_check(receiver, T_OBJECT); _sp -= nargs; return receiver; }
//============================================================================= //------------------------------do_monitor_enter------------------------------- void Parse::do_monitor_enter() { kill_dead_locals(); // Null check; get casted pointer. Node *obj = do_null_check(peek(), T_OBJECT); // Check for locking null object if (stopped()) return; // the monitor object is not part of debug info expression stack pop(); // Insert a FastLockNode which takes as arguments the current thread pointer, // the obj pointer & the address of the stack slot pair used for the lock. shared_lock(obj); }
// uncommon-trap call-sites where callee is unloaded, uninitialized or will not link bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) { // Additional inputs to consider... // bc = bc() // caller = method() // iter().get_method_holder_index() assert( dest_method->is_loaded(), "ciTypeFlow should not let us get here" ); // Interface classes can be loaded & linked and never get around to // being initialized. Uncommon-trap for not-initialized static or // v-calls. Let interface calls happen. ciInstanceKlass* holder_klass = dest_method->holder(); if (!holder_klass->is_initialized() && !holder_klass->is_interface()) { if( method()->is_static() && method()->name() == ciSymbol::class_initializer_name() ) return false; // OK to inline inside of <clinit> if( method()->name() == ciSymbol::object_initializer_name() ) // because any thread calling the constructor must first have // synchronized on the class by executing a '_new' bytecode. return false; // Here we have decided that we cannot make the call because the method // holder is not initialized. We can still check for a null-receiver at // runtime and throw the NPE - which avoids a deopt if the user is // expecting the NPE. if(!dest_method->is_static()){ int nargs=1+dest_method->signature()->size(); assert(sp()>=nargs,"stack accepts only positive values"); Node*receiver=stack(sp()-nargs); receiver = do_null_check(receiver, T_OBJECT, "nullchk receiver"); } uncommon_trap(Deoptimization::Reason_uninitialized,holder_klass,"call site where called method holder is not initialized",false); return true; } assert(dest_method->will_link(method()->holder(), klass, bc()), "dest_method: typeflow responsibility"); return false; }