//------------------------------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 ); }
//------------------------------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); }