< prev index next >

src/hotspot/share/opto/parseHelper.cpp

Print this page

        

@@ -21,19 +21,22 @@
  * 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/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,10 +66,11 @@
 //=============================================================================
 //------------------------------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,

@@ -90,11 +94,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 +142,31 @@
   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);
 
+  const TypeAryPtr* ary_t = _gvn.type(ary)->is_aryptr();
+  const Type* elemtype = ary_t->elem();
+  const TypeOopPtr* elemptr = elemtype->make_oopptr();
+  bool is_value_array = elemtype->isa_valuetype() != NULL || (elemptr != NULL && elemptr->is_valuetypeptr());
+
   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.

@@ -219,25 +227,41 @@
   }
 
   // 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
+  if (is_value_array) {
+    // We statically know that this is a value type array, use precise klass ptr
+    ciValueKlass* vk = elemtype->isa_valuetype() ? elemtype->is_valuetype()->value_klass() :
+                                                   elemptr->value_klass();
+    a_e_klass = makecon(TypeKlassPtr::make(vk));
+  }
+
   // 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);
 }
 
 
 void Parse::emit_guard_for_new(ciInstanceKlass* klass) {
+  if ((!klass->is_initialized() && !klass->is_being_initialized()) ||
+      klass->is_abstract() || klass->is_interface() ||
+      klass->name() == ciSymbol::java_lang_Class() ||
+      iter().is_unresolved_klass()) {
+    uncommon_trap(Deoptimization::Reason_uninitialized,
+                  Deoptimization::Action_reinterpret,
+                  klass);
+  } if (klass->is_being_initialized()) {
   // Emit guarded new
   //   if (klass->_init_thread != current_thread ||
   //       klass->_init_state != being_initialized)
   //      uncommon_trap
   Node* cur_thread = _gvn.transform( new ThreadLocalNode() );

@@ -269,10 +293,11 @@
   set_control(merge);
 
   uncommon_trap(Deoptimization::Reason_uninitialized,
                 Deoptimization::Action_reinterpret,
                 klass);
+  }
 }
 
 
 //------------------------------do_new-----------------------------------------
 void Parse::do_new() {

@@ -281,22 +306,12 @@
   bool will_link;
   ciInstanceKlass* klass = iter().get_klass(will_link)->as_instance_klass();
   assert(will_link, "_new: typeflow responsibility");
 
   // Should initialize, or throw an InstantiationError?
-  if ((!klass->is_initialized() && !klass->is_being_initialized()) ||
-      klass->is_abstract() || klass->is_interface() ||
-      klass->name() == ciSymbol::java_lang_Class() ||
-      iter().is_unresolved_klass()) {
-    uncommon_trap(Deoptimization::Reason_uninitialized,
-                  Deoptimization::Action_reinterpret,
-                  klass);
-    return;
-  }
-  if (klass->is_being_initialized()) {
     emit_guard_for_new(klass);
-  }
+  if (stopped()) return;
 
   Node* kls = makecon(TypeKlassPtr::make(klass));
   Node* obj = new_instance(kls);
 
   // Push resultant oop onto stack

@@ -314,10 +329,67 @@
   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 initialize, or throw an InstantiationError?
+  emit_guard_for_new(vk);
+  if (stopped()) return;
+
+  // Always scalarize default value because it's not NULL by definition
+  push(ValueTypeNode::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");
+  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 >