< prev index next >

src/hotspot/share/opto/parseHelper.cpp

Print this page

        

@@ -21,19 +21,23 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "compiler/compileLog.hpp"
 #include "oops/objArrayKlass.hpp"
+#include "oops/valueArrayKlass.hpp"
 #include "opto/addnode.hpp"
+#include "opto/castnode.hpp"
 #include "opto/memnode.hpp"
 #include "opto/mulnode.hpp"
 #include "opto/parse.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/runtime.hpp"
+#include "opto/valuetypenode.hpp"
 #include "runtime/sharedRuntime.hpp"
 
 //------------------------------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) {

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

@@ -90,11 +96,14 @@
       profile_null_checkcast();
     }
     return;
   }
 
-  Node *res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass)) );
+  Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass)), NULL, never_null);
+  if (stopped()) {
+    return;
+  }
 
   // Pop from stack AFTER gen_checkcast because it can uncommon trap and
   // the debug info has to be correct.
   pop();
   push(res);

@@ -135,30 +144,26 @@
   push(res);
 }
 
 //------------------------------array_store_check------------------------------
 // pull array from stack and check that the store is valid
-void Parse::array_store_check() {
-
+Node* 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;
+    return obj;
   }
 
   // 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));
+  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.

@@ -207,10 +212,13 @@
     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);
+      Node* cast = _gvn.transform(new CheckCastPPNode(control(), ary, extak->as_instance_type()));
+      replace_in_map(ary, cast);
+
       CompileLog* log = C->log();
       if (log != NULL) {
         log->elem("cast_up reason='monomorphic_array' from='%d' to='(exact)'",
                   log->identify(tak->klass()));
       }

@@ -219,21 +227,28 @@
   }
 
   // Come here for polymorphic array klasses
 
   // Extract the array element class
-  int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset());
+  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));
 
+  // Handle value type arrays
+  const Type* elemtype = _gvn.type(ary)->is_aryptr()->elem();
+  if (elemtype->isa_valuetype() != NULL || elemtype->is_valuetypeptr()) {
+    // We statically know that this is a value type array, use precise klass ptr
+    a_e_klass = makecon(TypeKlassPtr::make(elemtype->value_klass()));
+  }
+
   // 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);
+  return gen_checkcast(obj, a_e_klass);
 }
 
 
 //------------------------------do_new-----------------------------------------
 void Parse::do_new() {

@@ -276,10 +291,80 @@
   if (C->eliminate_boxing() && klass->is_box_klass()) {
     C->set_has_boxed_value(true);
   }
 }
 
+//------------------------------do_defaultvalue---------------------------------
+void Parse::do_defaultvalue() {
+  bool will_link;
+  ciValueKlass* vk = iter().get_klass(will_link)->as_value_klass();
+  assert(will_link, "defaultvalue: typeflow responsibility");
+
+  // Should throw an InstantiationError?
+  if (iter().is_unresolved_klass()) {
+    uncommon_trap(Deoptimization::Reason_unhandled,
+                  Deoptimization::Action_none,
+                  vk);
+    return;
+  }
+
+  if (C->needs_clinit_barrier(vk, method())) {
+    clinit_barrier(vk, method());
+    if (stopped())  return;
+  }
+
+  ValueTypeNode* vt = ValueTypeNode::make_default(_gvn, vk);
+  if (vk->is_scalarizable()) {
+    push(vt);
+  } else {
+    push(vt->get_oop());
+  }
+}
+
+//------------------------------do_withfield------------------------------------
+void Parse::do_withfield() {
+  bool will_link;
+  ciField* field = iter().get_field(will_link);
+  assert(will_link, "withfield: typeflow responsibility");
+  BasicType bt = field->layout_type();
+  Node* val = type2size[bt] == 1 ? pop() : pop_pair();
+  ciValueKlass* holder_klass = field->holder()->as_value_klass();
+  Node* holder = pop();
+
+  if (!holder->is_ValueType()) {
+    // Null check and scalarize value type holder
+    inc_sp(2);
+    holder = null_check(holder);
+    dec_sp(2);
+    if (stopped()) return;
+    holder = ValueTypeNode::make_from_oop(this, holder, holder_klass);
+  }
+  if (!val->is_ValueType() && field->is_flattenable()) {
+    // Null check and scalarize value type field value
+    inc_sp(2);
+    val = null_check(val);
+    dec_sp(2);
+    if (stopped()) return;
+    val = ValueTypeNode::make_from_oop(this, val, gvn().type(val)->value_klass());
+  } else if (val->is_ValueType() && !field->is_flattenable()) {
+    // Non-flattenable field should not be scalarized
+    val = ValueTypePtrNode::make_from_value_type(this, val->as_ValueType());
+  }
+
+  // Clone the value type node and set the new field value
+  ValueTypeNode* new_vt = holder->clone()->as_ValueType();
+  new_vt->set_oop(_gvn.zerocon(T_VALUETYPE));
+  gvn().set_type(new_vt, new_vt->bottom_type());
+  new_vt->set_field_value_by_offset(field->offset(), val);
+
+  if (holder_klass->is_scalarizable()) {
+    push(_gvn.transform(new_vt));
+  } else {
+    push(new_vt->allocate(this)->get_oop());
+  }
+}
+
 #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 >