< prev index next >

src/share/vm/opto/parse1.cpp

Print this page

        

@@ -779,12 +779,12 @@
   gvn().set_type_bottom(memphi);
   _exits.set_i_o(iophi);
   _exits.set_all_memory(memphi);
 
   // Add a return value to the exit state.  (Do not push it yet.)
-  if (tf()->range()->cnt() > TypeFunc::Parms) {
-    const Type* ret_type = tf()->range()->field_at(TypeFunc::Parms);
+  if (tf()->range_sig()->cnt() > TypeFunc::Parms) {
+    const Type* ret_type = tf()->range_sig()->field_at(TypeFunc::Parms);
     if (ret_type->isa_int()) {
       BasicType ret_bt = method()->return_type()->basic_type();
       if (ret_bt == T_BOOLEAN ||
           ret_bt == T_CHAR ||
           ret_bt == T_BYTE ||

@@ -798,37 +798,40 @@
     // types will not join when we transform and push in do_exits().
     const TypeOopPtr* ret_oop_type = ret_type->isa_oopptr();
     if (ret_oop_type && !ret_oop_type->klass()->is_loaded()) {
       ret_type = TypeOopPtr::BOTTOM;
     }
-    if (_caller->has_method() && ret_type->isa_valuetypeptr()) {
-      // When inlining, return value type as ValueTypeNode not as oop
+    if ((_caller->has_method() || tf()->returns_value_type_as_fields()) &&
+        ret_type->isa_valuetypeptr() &&
+        ret_type->is_valuetypeptr()->klass() != C->env()->___Value_klass()) {
+      // When inlining or with multiple return values: return value
+      // type as ValueTypeNode not as oop
       ret_type = ret_type->is_valuetypeptr()->value_type();
     }
     int         ret_size = type2size[ret_type->basic_type()];
     Node*       ret_phi  = new PhiNode(region, ret_type);
     gvn().set_type_bottom(ret_phi);
     _exits.ensure_stack(ret_size);
-    assert((int)(tf()->range()->cnt() - TypeFunc::Parms) == ret_size, "good tf range");
+    assert((int)(tf()->range_sig()->cnt() - TypeFunc::Parms) == ret_size, "good tf range");
     assert(method()->return_type()->size() == ret_size, "tf agrees w/ method");
     _exits.set_argument(0, ret_phi);  // here is where the parser finds it
     // Note:  ret_phi is not yet pushed, until do_exits.
   }
 }
 
 // Helper function to create a ValueTypeNode from its fields passed as
 // arguments. Fields are passed in order of increasing offsets.
-Node* Compile::create_vt_node(Node* n, ciValueKlass* vk, ciValueKlass* base_vk, int base_offset, int base_input) {
+Node* Compile::create_vt_node(Node* n, ciValueKlass* vk, ciValueKlass* base_vk, int base_offset, int base_input, bool in) {
   assert(base_offset >= 0, "offset in value type always positive");
   PhaseGVN& gvn = *initial_gvn();
   ValueTypeNode* vt = ValueTypeNode::make(gvn, vk);
   for (uint i = 0; i < vt->field_count(); i++) {
     ciType* field_type = vt->field_type(i);
     int offset = base_offset + vt->field_offset(i) - (base_offset > 0 ? vk->first_field_offset() : 0);
     if (field_type->is_valuetype()) {
       ciValueKlass* embedded_vk = field_type->as_value_klass();
-      Node* embedded_vt = create_vt_node(n, embedded_vk, base_vk, offset, base_input);
+      Node* embedded_vt = create_vt_node(n, embedded_vk, base_vk, offset, base_input, in);
       vt->set_field_value(i, embedded_vt);
     } else {
       int j = 0; int extra = 0;
       for (; j < base_vk->nof_nonstatic_fields(); j++) {
         ciField* f = base_vk->nonstatic_field_at(j);

@@ -842,14 +845,19 @@
         }
       }
       assert(j != base_vk->nof_nonstatic_fields(), "must find");
       Node* parm = NULL;
       if (n->is_Start()) {
+        assert(in, "return from start?");
         parm = gvn.transform(new ParmNode(n->as_Start(), base_input + j + extra));
       } else {
+        if (in) {
         assert(n->is_Call(), "nothing else here");
         parm = n->in(base_input + j + extra);
+        } else {
+          parm = gvn.transform(new ProjNode(n->as_Call(), base_input + j + extra));
+        }
       }
       vt->set_field_value(i, parm);
       // Record all these guys for later GVN.
       record_for_igvn(parm);
     }

@@ -860,11 +868,11 @@
 //----------------------------build_start_state-------------------------------
 // Construct a state which contains only the incoming arguments from an
 // unknown caller.  The method & bci will be NULL & InvocationEntryBci.
 JVMState* Compile::build_start_state(StartNode* start, const TypeFunc* tf) {
   int        arg_size_sig = tf->domain_sig()->cnt();
-  int        max_size = MAX2(arg_size_sig, (int)tf->range()->cnt());
+  int        max_size = MAX2(arg_size_sig, (int)tf->range_cc()->cnt());
   JVMState*  jvms     = new (this) JVMState(max_size - TypeFunc::Parms);
   SafePointNode* map  = new SafePointNode(max_size, NULL);
   record_for_igvn(map);
   assert(arg_size_sig == TypeFunc::Parms + (is_osr_compilation() ? 1 : method()->arg_size()), "correct arg_size");
   Node_Notes* old_nn = default_node_notes();

@@ -893,11 +901,11 @@
         // argument per field of the value type. Build ValueTypeNodes
         // from the value type arguments.
         const Type* t = tf->domain_sig()->field_at(i);
         if (t->isa_valuetypeptr() && t->is_valuetypeptr()->klass() != C->env()->___Value_klass()) {
           ciValueKlass* vk = t->is_valuetypeptr()->value_type()->value_klass();
-          Node* vt = create_vt_node(start, vk, vk, 0, j);
+          Node* vt = create_vt_node(start, vk, vk, 0, j, true);
           map->init_req(i, gvn.transform(vt));
           j += vk->value_arg_slots();
         } else {
           Node* parm = gvn.transform(new ParmNode(start, j));
           map->init_req(i, parm);

@@ -950,17 +958,28 @@
                              kit.i_o(),
                              kit.reset_memory(),
                              kit.frameptr(),
                              kit.returnadr());
   // Add zero or 1 return values
-  int ret_size = tf()->range()->cnt() - TypeFunc::Parms;
+  int ret_size = tf()->range_sig()->cnt() - TypeFunc::Parms;
   if (ret_size > 0) {
     kit.inc_sp(-ret_size);  // pop the return value(s)
     kit.sync_jvms();
-    ret->add_req(kit.argument(0));
+    Node* res = kit.argument(0);
+    if (tf()->returns_value_type_as_fields()) {
+      // Multiple return values (value type fields): add as many edges
+      // to the Return node as returned values.
+      assert(res->is_ValueType(), "what else supports multi value return");
+      ValueTypeNode* vt = res->as_ValueType();
+      ret->add_req_batch(NULL, tf()->range_cc()->cnt() - TypeFunc::Parms);
+      vt->pass_klass(ret, TypeFunc::Parms, kit);
+      vt->pass_fields(ret, TypeFunc::Parms+1, kit);
+    } else {
+      ret->add_req(res);
     // Note:  The second dummy edge is not needed by a ReturnNode.
   }
+  }
   // bind it to root
   root()->add_req(ret);
   record_for_igvn(ret);
   initial_gvn()->transform_no_reclaim(ret);
 }

@@ -1112,12 +1131,12 @@
   for (MergeMemStream mms(_exits.merged_memory()); mms.next_non_empty(); ) {
     // transform each slice of the original memphi:
     mms.set_memory(_gvn.transform(mms.memory()));
   }
 
-  if (tf()->range()->cnt() > TypeFunc::Parms) {
-    const Type* ret_type = tf()->range()->field_at(TypeFunc::Parms);
+  if (tf()->range_sig()->cnt() > TypeFunc::Parms) {
+    const Type* ret_type = tf()->range_sig()->field_at(TypeFunc::Parms);
     Node*       ret_phi  = _gvn.transform( _exits.argument(0) );
     if (!_exits.control()->is_top() && _gvn.type(ret_phi)->empty()) {
       // In case of concurrent class loading, the type we set for the
       // ret_phi in build_exits() may have been too optimistic and the
       // ret_phi may be top now.

@@ -2292,22 +2311,27 @@
 }
 
 //------------------------------return_current---------------------------------
 // Append current _map to _exit_return
 void Parse::return_current(Node* value) {
-  if (value != NULL && value->is_ValueType() && !_caller->has_method()) {
-    // Returning from root JVMState, make sure value type is allocated
+  if (value != NULL && value->is_ValueType() && !_caller->has_method() &&
+      !tf()->returns_value_type_as_fields()) {
+    // Returning from root JVMState without multiple returned values,
+    // make sure value type is allocated
     value = value->as_ValueType()->store_to_memory(this);
   }
 
   if (RegisterFinalizersAtInit &&
       method()->intrinsic_id() == vmIntrinsics::_Object_init) {
     call_register_finalizer();
   }
 
   // Do not set_parse_bci, so that return goo is credited to the return insn.
-  set_bci(InvocationEntryBci);
+  // vreturn can trigger an allocation so vreturn can throw. Setting
+  // the bci here breaks exception handling. Commenting this out
+  // doesn't seem to break anything.
+  //  set_bci(InvocationEntryBci);
   if (method()->is_synchronized() && GenerateSynchronizationCode) {
     shared_unlock(_synch_lock->box_node(), _synch_lock->obj_node());
   }
   if (C->env()->dtrace_method_probes()) {
     make_dtrace_method_exit(method());
< prev index next >