< prev index next >

src/hotspot/share/opto/parseHelper.cpp

Print this page
*** 21,14 ***
--- 21,18 ---
   * questions.
   *
   */
  
  #include "precompiled.hpp"
+ #include "ci/ciInlineKlass.hpp"
  #include "ci/ciSymbols.hpp"
  #include "compiler/compileLog.hpp"
+ #include "oops/flatArrayKlass.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "opto/addnode.hpp"
+ #include "opto/castnode.hpp"
+ #include "opto/inlinetypenode.hpp"
  #include "opto/memnode.hpp"
  #include "opto/mulnode.hpp"
  #include "opto/parse.hpp"
  #include "opto/rootnode.hpp"
  #include "opto/runtime.hpp"

*** 63,18 ***
  //=============================================================================
  //------------------------------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->is_loaded())) {
      if (C->log() != NULL) {
        if (!will_link) {
          C->log()->elem("assert_null reason='checkcast' klass='%d'",
                         C->log()->identify(klass));
        }
--- 67,19 ---
  //=============================================================================
  //------------------------------do_checkcast-----------------------------------
  void Parse::do_checkcast() {
    bool will_link;
    ciKlass* klass = iter().get_klass(will_link);
!   bool null_free = iter().has_Q_signature();
    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->is_loaded())) {
+     assert(!null_free, "Inline type should be loaded");
      if (C->log() != NULL) {
        if (!will_link) {
          C->log()->elem("assert_null reason='checkcast' klass='%d'",
                         C->log()->identify(klass));
        }

*** 88,11 ***
      null_assert(obj);
      assert( stopped() || _gvn.type(peek())->higher_equal(TypePtr::NULL_PTR), "what's left behind is null" );
      return;
    }
  
!   Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass, Type::trust_interfaces)));
    if (stopped()) {
      return;
    }
  
    // Pop from stack AFTER gen_checkcast because it can uncommon trap and
--- 93,11 ---
      null_assert(obj);
      assert( stopped() || _gvn.type(peek())->higher_equal(TypePtr::NULL_PTR), "what's left behind is null" );
      return;
    }
  
!   Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass, Type::trust_interfaces)), NULL, null_free);
    if (stopped()) {
      return;
    }
  
    // Pop from stack AFTER gen_checkcast because it can uncommon trap and

*** 136,44 ***
    push(res);
  }
  
  //------------------------------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 != TypeInstKlassPtr::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,
--- 141,63 ---
    push(res);
  }
  
  //------------------------------array_store_check------------------------------
  // pull array from stack and check that the store is valid
! Node* Parse::array_store_check(Node*& adr, const Type*& elemtype) {
    // 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.
!     if (_gvn.type(ary)->is_aryptr()->is_null_free()) {
+       null_check(obj);
+     }
+     return obj;
    }
  
    // Extract the array klass type
!   Node* array_klass = load_object_klass(ary);
    // 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 && !tak->klass_is_exact()) {
!     // Make a constant out of the inexact array klass
!     const TypeKlassPtr* extak = NULL;
!     const TypeOopPtr* ary_t = _gvn.type(ary)->is_oopptr();
!     ciKlass* ary_spec = ary_t->speculative_type();
!     Deoptimization::DeoptReason reason = Deoptimization::Reason_none;
+     // Try to cast the array to an exact type from profile data. First
+     // check the speculative type.
+     if (ary_spec != NULL && !too_many_traps(Deoptimization::Reason_speculate_class_check)) {
+       extak = TypeKlassPtr::make(ary_spec);
+       reason = Deoptimization::Reason_speculate_class_check;
+     } else if (UseArrayLoadStoreProfile) {
+       // No speculative type: check profile data at this bci.
+       reason = Deoptimization::Reason_class_check;
+       if (!too_many_traps(reason)) {
+         ciKlass* array_type = NULL;
+         ciKlass* element_type = NULL;
+         ProfilePtrKind element_ptr = ProfileMaybeNull;
+         bool flat_array = true;
+         bool null_free_array = true;
+         method()->array_access_profiled_type(bci(), array_type, element_type, element_ptr, flat_array, null_free_array);
+         if (array_type != NULL) {
+           extak = TypeKlassPtr::make(array_type);
+         }
+       }
+     } else if (!too_many_traps(Deoptimization::Reason_array_check) && tak != TypeInstKlassPtr::OBJECT) {
        // 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,

*** 188,66 ***
        // 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);
- 
-     if (extak->exact_klass(true) != NULL) {
        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,
!                       extak->exact_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(extak->exact_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);
  }
  
  
  //------------------------------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 throw an InstantiationError?
    if (klass->is_abstract() || klass->is_interface() ||
        klass->name() == ciSymbols::java_lang_Class() ||
        iter().is_unresolved_klass()) {
--- 212,80 ---
        // 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.
!       extak = tak->cast_to_exactness(true);
!       reason = Deoptimization::Reason_array_check;
!     }
!     if (extak != NULL && extak->exact_klass(true) != NULL) {
        Node* con = makecon(extak);
!       Node* cmp = _gvn.transform(new CmpPNode(array_klass, con));
!       Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
!       // Only do it if the check does not always pass/fail
!       if (!bol->is_Con()) {
!         always_see_exact_class = true;
!         { BuildCutout unless(this, bol, PROB_MAX);
!           uncommon_trap(reason,
!                         Deoptimization::Action_maybe_recompile,
!                         extak->exact_klass());
!         }
!         // Cast array klass to exactness
!         replace_in_map(array_klass, con);
!         array_klass = con;
+         Node* cast = _gvn.transform(new CheckCastPPNode(control(), ary, extak->as_instance_type()));
+         replace_in_map(ary, cast);
+         ary = cast;
+ 
+         // Recompute element type and address
+         const TypeAryPtr* arytype = _gvn.type(ary)->is_aryptr();
+         elemtype = arytype->elem();
+         adr = array_element_address(ary, idx, T_OBJECT, arytype->size(), control());
+ 
          CompileLog* log = C->log();
          if (log != NULL) {
            log->elem("cast_up reason='monomorphic_array' from='%d' to='(exact)'",
                      log->identify(extak->exact_klass()));
          }
        }
      }
    }
  
    // Come here for polymorphic array klasses
  
    // Extract the array element class
!   int element_klass_offset = in_bytes(ArrayKlass::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));
  
+   // If we statically know that this is an inline type array, use precise element klass for checkcast
+   const TypeAryPtr* arytype = _gvn.type(ary)->is_aryptr();
+   bool null_free = false;
+   if (elemtype->make_ptr()->is_inlinetypeptr()) {
+     // We statically know that this is an inline type array, use precise klass ptr
+     null_free = arytype->is_flat() || !elemtype->make_ptr()->maybe_null();
+     a_e_klass = makecon(TypeKlassPtr::make(elemtype->inline_klass()));
+   }
+ 
    // Check (the hard way) and throw if not a subklass.
!   return gen_checkcast(obj, a_e_klass, NULL, null_free);
  }
  
  
  //------------------------------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");
+   assert(!klass->is_inlinetype(), "unexpected inline type");
  
    // Should throw an InstantiationError?
    if (klass->is_abstract() || klass->is_interface() ||
        klass->name() == ciSymbols::java_lang_Class() ||
        iter().is_unresolved_klass()) {

*** 280,10 ***
--- 318,67 ---
    if (C->eliminate_boxing() && klass->is_box_klass()) {
      C->set_has_boxed_value(true);
    }
  }
  
+ //------------------------------do_aconst_init---------------------------------
+ void Parse::do_aconst_init() {
+   bool will_link;
+   ciInlineKlass* vk = iter().get_klass(will_link)->as_inline_klass();
+   assert(will_link && !iter().is_unresolved_klass(), "aconst_init: typeflow responsibility");
+ 
+   if (C->needs_clinit_barrier(vk, method())) {
+     clinit_barrier(vk, method());
+     if (stopped())  return;
+   }
+ 
+   push(InlineTypeNode::make_default(_gvn, vk));
+ }
+ 
+ //------------------------------do_withfield------------------------------------
+ void Parse::do_withfield() {
+   bool will_link;
+   ciField* field = iter().get_field(will_link);
+   assert(will_link, "withfield: typeflow responsibility");
+   int holder_depth = field->type()->size();
+   null_check(peek(holder_depth));
+   if (stopped()) {
+     return;
+   }
+   Node* val = pop_node(field->layout_type());
+   Node* holder = pop();
+ 
+   if (!val->is_InlineType() && field->type()->is_inlinetype()) {
+     // Scalarize inline type field value
+     assert(!field->is_null_free() || !gvn().type(val)->maybe_null(), "Null store to null-free field");
+     val = InlineTypeNode::make_from_oop(this, val, field->type()->as_inline_klass(), field->is_null_free());
+   } else if (val->is_InlineType() && !field->is_null_free()) {
+     // Field value needs to be allocated because it can be merged with an oop.
+     // Re-execute withfield if buffering triggers deoptimization.
+     PreserveReexecuteState preexecs(this);
+     jvms()->set_should_reexecute(true);
+     int nargs = 1 + field->type()->size();
+     inc_sp(nargs);
+     val = val->as_InlineType()->buffer(this);
+   }
+ 
+   // Clone the inline type node and set the new field value
+   InlineTypeNode* new_vt = InlineTypeNode::make_uninitialized(gvn(), gvn().type(holder)->inline_klass());
+   for (uint i = 2; i < holder->req(); ++i) {
+     new_vt->set_req(i, holder->in(i));
+   }
+   new_vt->set_field_value_by_offset(field->offset(), val);
+   {
+     PreserveReexecuteState preexecs(this);
+     jvms()->set_should_reexecute(true);
+     int nargs = 1 + field->type()->size();
+     inc_sp(nargs);
+     new_vt = new_vt->adjust_scalarization_depth(this);
+   }
+   push(_gvn.transform(new_vt));
+ }
+ 
  #ifndef PRODUCT
  //------------------------------dump_map_adr_mem-------------------------------
  // Debug dump of the mapping from address types to MergeMemNode indices.
  void Parse::dump_map_adr_mem() const {
    tty->print_cr("--- Mapping from address types to memory Nodes ---");
< prev index next >