< prev index next >

src/hotspot/share/opto/matcher.cpp

Print this page

        

@@ -169,10 +169,56 @@
     }
   }
 }
 #endif
 
+// Array of RegMask, one per returned values (value type instances can
+// be returned as multiple return values, one per field)
+RegMask* Matcher::return_values_mask(const TypeTuple *range) {
+  uint cnt = range->cnt() - TypeFunc::Parms;
+  if (cnt == 0) {
+    return NULL;
+  }
+  RegMask* mask = NEW_RESOURCE_ARRAY(RegMask, cnt);
+
+  if (!ValueTypeReturnedAsFields) {
+    // Get ideal-register return type
+    uint ireg = range->field_at(TypeFunc::Parms)->ideal_reg();
+    // Get machine return register
+    OptoRegPair regs = return_value(ireg, false);
+
+    // And mask for same
+    mask[0].Clear();
+    mask[0].Insert(regs.first());
+    if (OptoReg::is_valid(regs.second())) {
+      mask[0].Insert(regs.second());
+    }
+  } else {
+    BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, cnt);
+    VMRegPair* vm_parm_regs = NEW_RESOURCE_ARRAY(VMRegPair, cnt);
+
+    for (uint i = 0; i < cnt; i++) {
+      sig_bt[i] = range->field_at(i+TypeFunc::Parms)->basic_type();
+    }
+
+    int regs = SharedRuntime::java_return_convention(sig_bt, vm_parm_regs, cnt);
+    assert(regs > 0, "should have been tested during graph construction");
+    for (uint i = 0; i < cnt; i++) {
+      mask[i].Clear();
+
+      OptoReg::Name reg1 = OptoReg::as_OptoReg(vm_parm_regs[i].first());
+      if (OptoReg::is_valid(reg1)) {
+        mask[i].Insert(reg1);
+      }
+      OptoReg::Name reg2 = OptoReg::as_OptoReg(vm_parm_regs[i].second());
+      if (OptoReg::is_valid(reg2)) {
+        mask[i].Insert(reg2);
+      }
+    }
+  }
+  return mask;
+}
 
 //---------------------------match---------------------------------------------
 void Matcher::match( ) {
   if( MaxLabelRootDepth < 100 ) { // Too small?
     assert(false, "invalid MaxLabelRootDepth, increase it to 100 minimum");

@@ -184,33 +230,22 @@
 #ifdef _LP64
   // Pointers take 2 slots in 64-bit land
   _return_addr_mask.Insert(OptoReg::add(return_addr(),1));
 #endif
 
-  // Map a Java-signature return type into return register-value
-  // machine registers for 0, 1 and 2 returned values.
-  const TypeTuple *range = C->tf()->range();
-  if( range->cnt() > TypeFunc::Parms ) { // If not a void function
-    // Get ideal-register return type
-    uint ireg = range->field_at(TypeFunc::Parms)->ideal_reg();
-    // Get machine return register
-    uint sop = C->start()->Opcode();
-    OptoRegPair regs = return_value(ireg, false);
-
-    // And mask for same
-    _return_value_mask = RegMask(regs.first());
-    if( OptoReg::is_valid(regs.second()) )
-      _return_value_mask.Insert(regs.second());
-  }
+  // Map Java-signature return types into return register-value
+  // machine registers.
+  const TypeTuple *range = C->tf()->range_cc();
+  _return_values_mask = return_values_mask(range);
 
   // ---------------
   // Frame Layout
 
   // Need the method signature to determine the incoming argument types,
   // because the types determine which registers the incoming arguments are
   // in, and this affects the matched code.
-  const TypeTuple *domain = C->tf()->domain();
+  const TypeTuple *domain = C->tf()->domain_cc();
   uint             argcnt = domain->cnt() - TypeFunc::Parms;
   BasicType *sig_bt        = NEW_RESOURCE_ARRAY( BasicType, argcnt );
   VMRegPair *vm_parm_regs  = NEW_RESOURCE_ARRAY( VMRegPair, argcnt );
   _parm_regs               = NEW_RESOURCE_ARRAY( OptoRegPair, argcnt );
   _calling_convention_mask = NEW_RESOURCE_ARRAY( RegMask, argcnt );

@@ -460,10 +495,29 @@
   // Add in the incoming argument area
   OptoReg::Name init_in = OptoReg::add(_old_SP, C->out_preserve_stack_slots());
   for (i = init_in; i < _in_arg_limit; i = OptoReg::add(i,1)) {
     C->FIRST_STACK_mask().Insert(i);
   }
+
+  // Check if the method has a reserved entry in the argument stack area that
+  // should not be used for spilling because it may hold the return address.
+  if (C->method() != NULL && C->method()->has_scalarized_args()) {
+    ExtendedSignature sig_cc = ExtendedSignature(C->method()->get_sig_cc(), SigEntryFilter());
+    for (int off = 0; !sig_cc.at_end(); ) {
+      BasicType bt = (*sig_cc)._bt;
+      off += type2size[bt];
+      while (SigEntry::next_is_reserved(sig_cc, bt)) {
+        // Remove reserved stack slot from mask to avoid spilling
+        OptoRegPair reg = _parm_regs[off];
+        assert(OptoReg::is_valid(reg.first()), "invalid reserved register");
+        C->FIRST_STACK_mask().Remove(reg.first());
+        C->FIRST_STACK_mask().Remove(reg.first()+1); // Always occupies two stack slots
+        off += type2size[bt];
+      }
+    }
+  }
+
   // Add in all bits past the outgoing argument area
   guarantee(RegMask::can_represent_arg(OptoReg::add(_out_arg_limit,-1)),
             "must be able to represent all call arguments in reg mask");
   OptoReg::Name init = _out_arg_limit;
   for (i = init; RegMask::can_represent(i); i = OptoReg::add(i,1)) {

@@ -652,16 +706,15 @@
         soe_cnt++;
 
   // Input RegMask array shared by all Returns.
   // The type for doubles and longs has a count of 2, but
   // there is only 1 returned value
-  uint ret_edge_cnt = TypeFunc::Parms + ((C->tf()->range()->cnt() == TypeFunc::Parms) ? 0 : 1);
+  uint ret_edge_cnt = C->tf()->range_cc()->cnt();
   RegMask *ret_rms  = init_input_masks( ret_edge_cnt + soe_cnt, _return_addr_mask, c_frame_ptr_mask );
-  // Returns have 0 or 1 returned values depending on call signature.
-  // Return register is specified by return_value in the AD file.
-  if (ret_edge_cnt > TypeFunc::Parms)
-    ret_rms[TypeFunc::Parms+0] = _return_value_mask;
+  for (i = TypeFunc::Parms; i < ret_edge_cnt; i++) {
+    ret_rms[i] = _return_values_mask[i-TypeFunc::Parms];
+  }
 
   // Input RegMask array shared by all Rethrows.
   uint reth_edge_cnt = TypeFunc::Parms+1;
   RegMask *reth_rms  = init_input_masks( reth_edge_cnt + soe_cnt, _return_addr_mask, c_frame_ptr_mask );
   // Rethrow takes exception oop only, but in the argument 0 slot.

@@ -724,11 +777,11 @@
       default          : ShouldNotReachHere();
     }
   }
 
   // Next unused projection number from Start.
-  int proj_cnt = C->tf()->domain()->cnt();
+  int proj_cnt = C->tf()->domain_cc()->cnt();
 
   // Do all the save-on-entry registers.  Make projections from Start for
   // them, and give them a use at the exit points.  To the allocator, they
   // look like incoming register arguments.
   for( i = 0; i < _last_Mach_Reg; i++ ) {

@@ -1005,11 +1058,15 @@
               m->as_MachMemBar()->set_adr_type(n->adr_type());
             }
           } else {                  // Nothing the matcher cares about
             if (n->is_Proj() && n->in(0) != NULL && n->in(0)->is_Multi()) {       // Projections?
               // Convert to machine-dependent projection
-              m = n->in(0)->as_Multi()->match( n->as_Proj(), this );
+              RegMask* mask = NULL;
+              if (n->in(0)->is_Call()) {
+                mask = return_values_mask(n->in(0)->as_Call()->tf()->range_cc());
+              }
+              m = n->in(0)->as_Multi()->match(n->as_Proj(), this, mask);
 #ifdef ASSERT
               _new2old_map.map(m->_idx, n);
 #endif
               if (m->in(0) != NULL) // m might be top
                 collect_null_checks(m, n);

@@ -1150,11 +1207,11 @@
   const TypeTuple *domain;
   ciMethod*        method = NULL;
   bool             is_method_handle_invoke = false;  // for special kill effects
   if( sfpt->is_Call() ) {
     call = sfpt->as_Call();
-    domain = call->tf()->domain();
+    domain = call->tf()->domain_cc();
     cnt = domain->cnt();
 
     // Match just the call, nothing else
     MachNode *m = match_tree(call);
     if (C->failing())  return NULL;

@@ -1225,17 +1282,20 @@
   if( call != NULL && call->is_CallRuntime() )
     out_arg_limit_per_call = OptoReg::add(out_arg_limit_per_call,C->varargs_C_out_slots_killed());
 
 
   // Do the normal argument list (parameters) register masks
-  int argcnt = cnt - TypeFunc::Parms;
+  // Null entry point is a special cast where the target of the call
+  // is in a register.
+  int adj = (call != NULL && call->entry_point() == NULL) ? 1 : 0;
+  int argcnt = cnt - TypeFunc::Parms - adj;
   if( argcnt > 0 ) {          // Skip it all if we have no args
     BasicType *sig_bt  = NEW_RESOURCE_ARRAY( BasicType, argcnt );
     VMRegPair *parm_regs = NEW_RESOURCE_ARRAY( VMRegPair, argcnt );
     int i;
     for( i = 0; i < argcnt; i++ ) {
-      sig_bt[i] = domain->field_at(i+TypeFunc::Parms)->basic_type();
+      sig_bt[i] = domain->field_at(i+TypeFunc::Parms+adj)->basic_type();
     }
     // V-call to pick proper calling convention
     call->calling_convention( sig_bt, parm_regs, argcnt );
 
 #ifdef ASSERT

@@ -1272,23 +1332,25 @@
     // Return results now can have 2 bits returned.
     // Compute max over all outgoing arguments both per call-site
     // and over the entire method.
     for( i = 0; i < argcnt; i++ ) {
       // Address of incoming argument mask to fill in
-      RegMask *rm = &mcall->_in_rms[i+TypeFunc::Parms];
+      RegMask *rm = &mcall->_in_rms[i+TypeFunc::Parms+adj];
       if( !parm_regs[i].first()->is_valid() &&
           !parm_regs[i].second()->is_valid() ) {
         continue;               // Avoid Halves
       }
       // Grab first register, adjust stack slots and insert in mask.
       OptoReg::Name reg1 = warp_outgoing_stk_arg(parm_regs[i].first(), begin_out_arg_area, out_arg_limit_per_call );
-      if (OptoReg::is_valid(reg1))
+      if (OptoReg::is_valid(reg1)) {
         rm->Insert( reg1 );
+      }
       // Grab second register (if any), adjust stack slots and insert in mask.
       OptoReg::Name reg2 = warp_outgoing_stk_arg(parm_regs[i].second(), begin_out_arg_area, out_arg_limit_per_call );
-      if (OptoReg::is_valid(reg2))
+      if (OptoReg::is_valid(reg2)) {
         rm->Insert( reg2 );
+      }
     } // End of for all arguments
 
     // Compute number of stack slots needed to restore stack in case of
     // Pascal-style argument popping.
     mcall->_argsize = out_arg_limit_per_call - begin_out_arg_area;

@@ -1304,11 +1366,11 @@
     // Kill the outgoing argument area, including any non-argument holes and
     // any legacy C-killed slots.  Use Fat-Projections to do the killing.
     // Since the max-per-method covers the max-per-call-site and debug info
     // is excluded on the max-per-method basis, debug info cannot land in
     // this killed area.
-    uint r_cnt = mcall->tf()->range()->cnt();
+    uint r_cnt = mcall->tf()->range_sig()->cnt();
     MachProjNode *proj = new MachProjNode( mcall, r_cnt+10000, RegMask::Empty, MachProjNode::fat_proj );
     if (!RegMask::can_represent_arg(OptoReg::Name(out_arg_limit_per_call-1))) {
       C->record_method_not_compilable("unsupported outgoing calling sequence");
     } else {
       for (int i = begin_out_arg_area; i < out_arg_limit_per_call; i++)

@@ -1325,11 +1387,11 @@
     jvms->set_map(sfpt);
   }
 
   // Debug inputs begin just after the last incoming parameter
   assert((mcall == NULL) || (mcall->jvms() == NULL) ||
-         (mcall->jvms()->debug_start() + mcall->_jvmadj == mcall->tf()->domain()->cnt()), "");
+         (mcall->jvms()->debug_start() + mcall->_jvmadj == mcall->tf()->domain_cc()->cnt()), "");
 
   // Move the OopMap
   msfpt->_oop_map = sfpt->_oop_map;
 
   // Add additional edges.

@@ -2360,10 +2422,17 @@
       n->set_req(2, pair2);
       n->del_req(4);
       n->del_req(3);
       break;
     }
+    case Op_ClearArray: {
+      Node* pair = new BinaryNode(n->in(2), n->in(3));
+      n->set_req(2, pair);
+      n->set_req(3, n->in(4));
+      n->del_req(4);
+      break;
+    }
     default:
       break;
   }
 }
 
< prev index next >