changeset 63:eac007780a58

6671807: (Escape Analysis) Add new ideal node to represent the state of a scalarized object at a safepoint Summary: Values of non-static fields of a scalarized object should be saved in debug info to reallocate the object during deoptimization. Reviewed-by: never
author kvn
date Thu, 13 Mar 2008 16:06:34 -0700
parents 8b6e49187640
children b8f5ba577b02
files src/share/vm/opto/callnode.cpp src/share/vm/opto/callnode.hpp src/share/vm/opto/classes.hpp src/share/vm/opto/compile.hpp src/share/vm/opto/graphKit.cpp src/share/vm/opto/macro.cpp src/share/vm/opto/matcher.cpp src/share/vm/opto/node.hpp src/share/vm/opto/output.cpp
diffstat 9 files changed, 322 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/opto/callnode.cpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/callnode.cpp	Thu Mar 13 16:06:34 2008 -0700
@@ -230,6 +230,7 @@
   _locoff = TypeFunc::Parms;
   _stkoff = _locoff + _method->max_locals();
   _monoff = _stkoff + _method->max_stack();
+  _scloff = _monoff;
   _endoff = _monoff;
   _sp = 0;
 }
@@ -242,6 +243,7 @@
   _locoff = TypeFunc::Parms;
   _stkoff = _locoff;
   _monoff = _stkoff + stack_size;
+  _scloff = _monoff;
   _endoff = _monoff;
   _sp = 0;
 }
@@ -297,12 +299,22 @@
   return total;
 }
 
+#ifndef PRODUCT
+
 //------------------------------format_helper----------------------------------
 // Given an allocation (a Chaitin object) and a Node decide if the Node carries
 // any defined value or not.  If it does, print out the register or constant.
-#ifndef PRODUCT
-static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, const char *msg, uint i ) {
+static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, const char *msg, uint i, GrowableArray<SafePointScalarObjectNode*> *scobjs ) {
   if (n == NULL) { st->print(" NULL"); return; }
+  if (n->is_SafePointScalarObject()) {
+    // Scalar replacement.
+    SafePointScalarObjectNode* spobj = n->as_SafePointScalarObject();
+    scobjs->append_if_missing(spobj);
+    int sco_n = scobjs->find(spobj);
+    assert(sco_n >= 0, "");
+    st->print(" %s%d]=#ScObj" INT32_FORMAT, msg, i, sco_n);
+    return;
+  }
   if( OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined
     char buf[50];
     regalloc->dump_register(n,buf);
@@ -342,10 +354,8 @@
     }
   }
 }
-#endif
 
 //------------------------------format-----------------------------------------
-#ifndef PRODUCT
 void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const {
   st->print("        #");
   if( _method ) {
@@ -356,24 +366,25 @@
     return;
   }
   if (n->is_MachSafePoint()) {
+    GrowableArray<SafePointScalarObjectNode*> scobjs;
     MachSafePointNode *mcall = n->as_MachSafePoint();
     uint i;
     // Print locals
     for( i = 0; i < (uint)loc_size(); i++ )
-      format_helper( regalloc, st, mcall->local(this, i), "L[", i );
+      format_helper( regalloc, st, mcall->local(this, i), "L[", i, &scobjs );
     // Print stack
     for (i = 0; i < (uint)stk_size(); i++) {
       if ((uint)(_stkoff + i) >= mcall->len())
         st->print(" oob ");
       else
-       format_helper( regalloc, st, mcall->stack(this, i), "STK[", i );
+       format_helper( regalloc, st, mcall->stack(this, i), "STK[", i, &scobjs );
     }
     for (i = 0; (int)i < nof_monitors(); i++) {
       Node *box = mcall->monitor_box(this, i);
       Node *obj = mcall->monitor_obj(this, i);
       if ( OptoReg::is_valid(regalloc->get_reg_first(box)) ) {
         while( !box->is_BoxLock() )  box = box->in(1);
-        format_helper( regalloc, st, box, "MON-BOX[", i );
+        format_helper( regalloc, st, box, "MON-BOX[", i, &scobjs );
       } else {
         OptoReg::Name box_reg = BoxLockNode::stack_slot(box);
         st->print(" MON-BOX%d=%s+%d",
@@ -381,15 +392,71 @@
                    OptoReg::regname(OptoReg::c_frame_pointer),
                    regalloc->reg2offset(box_reg));
       }
-      format_helper( regalloc, st, obj, "MON-OBJ[", i );
+      format_helper( regalloc, st, obj, "MON-OBJ[", i, &scobjs );
+    }
+
+    for (i = 0; i < (uint)scobjs.length(); i++) {
+      // Scalar replaced objects.
+      st->print_cr("");
+      st->print("        # ScObj" INT32_FORMAT " ", i);
+      SafePointScalarObjectNode* spobj = scobjs.at(i);
+      ciKlass* cik = spobj->bottom_type()->is_oopptr()->klass();
+      assert(cik->is_instance_klass() ||
+             cik->is_array_klass(), "Not supported allocation.");
+      ciInstanceKlass *iklass = NULL;
+      if (cik->is_instance_klass()) {
+        cik->print_name_on(st);
+        iklass = cik->as_instance_klass();
+      } else if (cik->is_type_array_klass()) {
+        cik->as_array_klass()->base_element_type()->print_name_on(st);
+        st->print("[%d]=", spobj->n_fields());
+      } else if (cik->is_obj_array_klass()) {
+        ciType* cie = cik->as_array_klass()->base_element_type();
+        int ndim = 1;
+        while (cie->is_obj_array_klass()) {
+          ndim += 1;
+          cie = cie->as_array_klass()->base_element_type();
+        }
+        cie->print_name_on(st);
+        while (ndim-- > 0) {
+          st->print("[]");
+        }
+        st->print("[%d]=", spobj->n_fields());
+      }
+      st->print("{");
+      uint nf = spobj->n_fields();
+      if (nf > 0) {
+        uint first_ind = spobj->first_index();
+        Node* fld_node = mcall->in(first_ind);
+        ciField* cifield;
+        if (iklass != NULL) {
+          st->print(" [");
+          cifield = iklass->nonstatic_field_at(0);
+          cifield->print_name_on(st);
+          format_helper( regalloc, st, fld_node, ":", 0, &scobjs );
+        } else {
+          format_helper( regalloc, st, fld_node, "[", 0, &scobjs );
+        }
+        for (uint j = 1; j < nf; j++) {
+          fld_node = mcall->in(first_ind+j);
+          if (iklass != NULL) {
+            st->print(", [");
+            cifield = iklass->nonstatic_field_at(j);
+            cifield->print_name_on(st);
+            format_helper( regalloc, st, fld_node, ":", j, &scobjs );
+          } else {
+            format_helper( regalloc, st, fld_node, ", [", j, &scobjs );
+          }
+        }
+      }
+      st->print(" }");
     }
   }
   st->print_cr("");
   if (caller() != NULL)  caller()->format(regalloc, n, st);
 }
-#endif
 
-#ifndef PRODUCT
+
 void JVMState::dump_spec(outputStream *st) const {
   if (_method != NULL) {
     bool printed = false;
@@ -419,9 +486,8 @@
   }
   if (caller() != NULL)  caller()->dump_spec(st);
 }
-#endif
 
-#ifndef PRODUCT
+
 void JVMState::dump_on(outputStream* st) const {
   if (_map && !((uintptr_t)_map & 1)) {
     if (_map->len() > _map->req()) {  // _map->has_exceptions()
@@ -434,8 +500,8 @@
     }
     _map->dump(2);
   }
-  st->print("JVMS depth=%d loc=%d stk=%d mon=%d end=%d mondepth=%d sp=%d bci=%d method=",
-             depth(), locoff(), stkoff(), monoff(), endoff(), monitor_depth(), sp(), bci());
+  st->print("JVMS depth=%d loc=%d stk=%d mon=%d scalar=%d end=%d mondepth=%d sp=%d bci=%d method=",
+             depth(), locoff(), stkoff(), monoff(), scloff(), endoff(), monitor_depth(), sp(), bci());
   if (_method == NULL) {
     st->print_cr("(none)");
   } else {
@@ -465,6 +531,7 @@
   n->set_locoff(_locoff);
   n->set_stkoff(_stkoff);
   n->set_monoff(_monoff);
+  n->set_scloff(_scloff);
   n->set_endoff(_endoff);
   n->set_sp(_sp);
   n->set_map(_map);
@@ -765,6 +832,7 @@
 void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) {
   assert((int)grow_by > 0, "sanity");
   int monoff = jvms->monoff();
+  int scloff = jvms->scloff();
   int endoff = jvms->endoff();
   assert(endoff == (int)req(), "no other states or debug info after me");
   Node* top = Compile::current()->top();
@@ -772,6 +840,7 @@
     ins_req(monoff, top);
   }
   jvms->set_monoff(monoff + grow_by);
+  jvms->set_scloff(scloff + grow_by);
   jvms->set_endoff(endoff + grow_by);
 }
 
@@ -781,6 +850,7 @@
   const int MonitorEdges = 2;
   assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges");
   assert(req() == jvms()->endoff(), "correct sizing");
+  int nextmon = jvms()->scloff();
   if (GenerateSynchronizationCode) {
     add_req(lock->box_node());
     add_req(lock->obj_node());
@@ -788,6 +858,7 @@
     add_req(NULL);
     add_req(NULL);
   }
+  jvms()->set_scloff(nextmon+MonitorEdges);
   jvms()->set_endoff(req());
 }
 
@@ -795,10 +866,13 @@
   // Delete last monitor from debug info
   debug_only(int num_before_pop = jvms()->nof_monitors());
   const int MonitorEdges = (1<<JVMState::logMonitorEdges);
+  int scloff = jvms()->scloff();
   int endoff = jvms()->endoff();
+  int new_scloff = scloff - MonitorEdges;
   int new_endoff = endoff - MonitorEdges;
+  jvms()->set_scloff(new_scloff);
   jvms()->set_endoff(new_endoff);
-  while (endoff > new_endoff)  del_req(--endoff);
+  while (scloff > new_scloff)  del_req(--scloff);
   assert(jvms()->nof_monitors() == num_before_pop-1, "");
 }
 
@@ -822,6 +896,63 @@
   return (TypeFunc::Parms == idx);
 }
 
+//==============  SafePointScalarObjectNode  ==============
+
+SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp,
+#ifdef ASSERT
+                                                     AllocateNode* alloc,
+#endif
+                                                     uint first_index,
+                                                     uint n_fields) :
+  TypeNode(tp, 1), // 1 control input -- seems required.  Get from root.
+#ifdef ASSERT
+  _alloc(alloc),
+#endif
+  _first_index(first_index),
+  _n_fields(n_fields)
+{
+  init_class_id(Class_SafePointScalarObject);
+}
+
+
+uint SafePointScalarObjectNode::ideal_reg() const {
+  return 0; // No matching to machine instruction
+}
+
+const RegMask &SafePointScalarObjectNode::in_RegMask(uint idx) const {
+  return *(Compile::current()->matcher()->idealreg2debugmask[in(idx)->ideal_reg()]);
+}
+
+const RegMask &SafePointScalarObjectNode::out_RegMask() const {
+  return RegMask::Empty;
+}
+
+uint SafePointScalarObjectNode::match_edge(uint idx) const {
+  return 0;
+}
+
+SafePointScalarObjectNode*
+SafePointScalarObjectNode::clone(int jvms_adj, Dict* sosn_map) const {
+  void* cached = (*sosn_map)[(void*)this];
+  if (cached != NULL) {
+    return (SafePointScalarObjectNode*)cached;
+  }
+  Compile* C = Compile::current();
+  SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone();
+  res->_first_index += jvms_adj;
+  sosn_map->Insert((void*)this, (void*)res);
+  return res;
+}
+
+
+#ifndef PRODUCT
+void SafePointScalarObjectNode::dump_spec(outputStream *st) const {
+  st->print(" # fields@[%d..%d]", first_index(),
+             first_index() + n_fields() - 1);
+}
+
+#endif
+
 //=============================================================================
 uint AllocateNode::size_of() const { return sizeof(*this); }
 
--- a/src/share/vm/opto/callnode.hpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/callnode.hpp	Thu Mar 13 16:06:34 2008 -0700
@@ -184,6 +184,7 @@
   uint              _locoff;    // Offset to locals in input edge mapping
   uint              _stkoff;    // Offset to stack in input edge mapping
   uint              _monoff;    // Offset to monitors in input edge mapping
+  uint              _scloff;    // Offset to fields of scalar objs in input edge mapping
   uint              _endoff;    // Offset to end of input edge mapping
   uint              _sp;        // Jave Expression Stack Pointer for this state
   int               _bci;       // Byte Code Index of this JVM point
@@ -207,16 +208,19 @@
   uint              stkoff() const { return _stkoff; }
   uint              argoff() const { return _stkoff + _sp; }
   uint              monoff() const { return _monoff; }
+  uint              scloff() const { return _scloff; }
   uint              endoff() const { return _endoff; }
   uint              oopoff() const { return debug_end(); }
 
   int            loc_size() const { return _stkoff - _locoff; }
   int            stk_size() const { return _monoff - _stkoff; }
-  int            mon_size() const { return _endoff - _monoff; }
+  int            mon_size() const { return _scloff - _monoff; }
+  int            scl_size() const { return _endoff - _scloff; }
 
   bool        is_loc(uint i) const { return i >= _locoff && i < _stkoff; }
   bool        is_stk(uint i) const { return i >= _stkoff && i < _monoff; }
-  bool        is_mon(uint i) const { return i >= _monoff && i < _endoff; }
+  bool        is_mon(uint i) const { return i >= _monoff && i < _scloff; }
+  bool        is_scl(uint i) const { return i >= _scloff && i < _endoff; }
 
   uint              sp()     const { return _sp; }
   int               bci()    const { return _bci; }
@@ -227,7 +231,9 @@
   uint              depth()  const { return _depth; }
   uint        debug_start()  const; // returns locoff of root caller
   uint        debug_end()    const; // returns endoff of self
-  uint        debug_size()   const { return loc_size() + sp() + mon_size(); }
+  uint        debug_size()   const {
+    return loc_size() + sp() + mon_size() + scl_size();
+  }
   uint        debug_depth()  const; // returns sum of debug_size values at all depths
 
   // Returns the JVM state at the desired depth (1 == root).
@@ -254,8 +260,11 @@
   void              set_locoff(uint off) { _locoff = off; }
   void              set_stkoff(uint off) { _stkoff = off; }
   void              set_monoff(uint off) { _monoff = off; }
+  void              set_scloff(uint off) { _scloff = off; }
   void              set_endoff(uint off) { _endoff = off; }
-  void              set_offsets(uint off) { _locoff = _stkoff = _monoff = _endoff = off; }
+  void              set_offsets(uint off) {
+    _locoff = _stkoff = _monoff = _scloff = _endoff = off;
+  }
   void              set_map(SafePointNode *map) { _map = map; }
   void              set_sp(uint sp) { _sp = sp; }
   void              set_bci(int bci) { _bci = bci; }
@@ -399,6 +408,47 @@
 #endif
 };
 
+//------------------------------SafePointScalarObjectNode----------------------
+// A SafePointScalarObjectNode represents the state of a scalarized object
+// at a safepoint.
+
+class SafePointScalarObjectNode: public TypeNode {
+  uint _first_index; // First input edge index of a SafePoint node where
+                     // states of the scalarized object fields are collected.
+  uint _n_fields;    // Number of non-static fields of the scalarized object.
+  DEBUG_ONLY(AllocateNode* _alloc);
+public:
+  SafePointScalarObjectNode(const TypeOopPtr* tp,
+#ifdef ASSERT
+                            AllocateNode* alloc,
+#endif
+                            uint first_index, uint n_fields);
+  virtual int Opcode() const;
+  virtual uint           ideal_reg() const;
+  virtual const RegMask &in_RegMask(uint) const;
+  virtual const RegMask &out_RegMask() const;
+  virtual uint           match_edge(uint idx) const;
+
+  uint first_index() const { return _first_index; }
+  uint n_fields()    const { return _n_fields; }
+  DEBUG_ONLY(AllocateNode* alloc() const { return _alloc; })
+
+  virtual uint size_of() const { return sizeof(*this); }
+
+  // Assumes that "this" is an argument to a safepoint node "s", and that
+  // "new_call" is being created to correspond to "s".  But the difference
+  // between the start index of the jvmstates of "new_call" and "s" is
+  // "jvms_adj".  Produce and return a SafePointScalarObjectNode that
+  // corresponds appropriately to "this" in "new_call".  Assumes that
+  // "sosn_map" is a map, specific to the translation of "s" to "new_call",
+  // mapping old SafePointScalarObjectNodes to new, to avoid multiple copies.
+  SafePointScalarObjectNode* clone(int jvms_adj, Dict* sosn_map) const;
+
+#ifndef PRODUCT
+  virtual void              dump_spec(outputStream *st) const;
+#endif
+};
+
 //------------------------------CallNode---------------------------------------
 // Call nodes now subsume the function of debug nodes at callsites, so they
 // contain the functionality of a full scope chain of debug nodes.
--- a/src/share/vm/opto/classes.hpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/classes.hpp	Thu Mar 13 16:06:34 2008 -0700
@@ -185,6 +185,7 @@
 macro(RoundDouble)
 macro(RoundFloat)
 macro(SafePoint)
+macro(SafePointScalarObject)
 macro(SCMemProj)
 macro(SinD)
 macro(SqrtD)
--- a/src/share/vm/opto/compile.hpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/compile.hpp	Thu Mar 13 16:06:34 2008 -0700
@@ -606,8 +606,20 @@
 
   // Build OopMaps for each GC point
   void BuildOopMaps();
-  // Append debug info for the node to the array
-  void FillLocArray( int idx, Node *local, GrowableArray<ScopeValue*> *array );
+
+  // Append debug info for the node "local" at safepoint node "sfpt" to the
+  // "array",   May also consult and add to "objs", which describes the
+  // scalar-replaced objects.
+  void FillLocArray( int idx, MachSafePointNode* sfpt,
+                     Node *local, GrowableArray<ScopeValue*> *array,
+                     GrowableArray<ScopeValue*> *objs );
+
+  // If "objs" contains an ObjectValue whose id is "id", returns it, else NULL.
+  static ObjectValue* sv_for_node_id(GrowableArray<ScopeValue*> *objs, int id);
+  // Requres that "objs" does not contains an ObjectValue whose id matches
+  // that of "sv.  Appends "sv".
+  static void set_sv_for_object_node(GrowableArray<ScopeValue*> *objs,
+                                     ObjectValue* sv );
 
   // Process an OopMap Element while emitting nodes
   void Process_OopMap_Node(MachNode *mach, int code_offset);
--- a/src/share/vm/opto/graphKit.cpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/graphKit.cpp	Thu Mar 13 16:06:34 2008 -0700
@@ -857,6 +857,13 @@
     for (j = 0; j < l; j++)
       call->set_req(p++, in_map->in(k+j));
 
+    // Copy any scalar object fields.
+    k = in_jvms->scloff();
+    l = in_jvms->scl_size();
+    out_jvms->set_scloff(p);
+    for (j = 0; j < l; j++)
+      call->set_req(p++, in_map->in(k+j));
+
     // Finish the new jvms.
     out_jvms->set_endoff(p);
 
@@ -864,6 +871,7 @@
     assert(out_jvms->depth()      == in_jvms->depth(),      "depth must match");
     assert(out_jvms->loc_size()   == in_jvms->loc_size(),   "size must match");
     assert(out_jvms->mon_size()   == in_jvms->mon_size(),   "size must match");
+    assert(out_jvms->scl_size()   == in_jvms->scl_size(),   "size must match");
     assert(out_jvms->debug_size() == in_jvms->debug_size(), "size must match");
 
     // Update the two tail pointers in parallel.
--- a/src/share/vm/opto/macro.cpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/macro.cpp	Thu Mar 13 16:06:34 2008 -0700
@@ -54,15 +54,30 @@
   uint new_dbg_start = newcall->tf()->domain()->cnt();
   int jvms_adj  = new_dbg_start - old_dbg_start;
   assert (new_dbg_start == newcall->req(), "argument count mismatch");
+
+  Dict* sosn_map = new Dict(cmpkey,hashkey);
   for (uint i = old_dbg_start; i < oldcall->req(); i++) {
-    newcall->add_req(oldcall->in(i));
+    Node* old_in = oldcall->in(i);
+    // Clone old SafePointScalarObjectNodes, adjusting their field contents.
+    if (old_in->is_SafePointScalarObject()) {
+      SafePointScalarObjectNode* old_sosn = old_in->as_SafePointScalarObject();
+      uint old_unique = C->unique();
+      Node* new_in = old_sosn->clone(jvms_adj, sosn_map);
+      if (old_unique != C->unique()) {
+        new_in = transform_later(new_in); // Register new node.
+      }
+      old_in = new_in;
+    }
+    newcall->add_req(old_in);
   }
+
   newcall->set_jvms(oldcall->jvms());
   for (JVMState *jvms = newcall->jvms(); jvms != NULL; jvms = jvms->caller()) {
     jvms->set_map(newcall);
     jvms->set_locoff(jvms->locoff()+jvms_adj);
     jvms->set_stkoff(jvms->stkoff()+jvms_adj);
     jvms->set_monoff(jvms->monoff()+jvms_adj);
+    jvms->set_scloff(jvms->scloff()+jvms_adj);
     jvms->set_endoff(jvms->endoff()+jvms_adj);
   }
 }
--- a/src/share/vm/opto/matcher.cpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/matcher.cpp	Thu Mar 13 16:06:34 2008 -0700
@@ -1647,6 +1647,7 @@
       case Op_Phi:             // Treat Phis as shared roots
       case Op_Parm:
       case Op_Proj:            // All handled specially during matching
+      case Op_SafePointScalarObject:
         set_shared(n);
         set_dontcare(n);
         break;
--- a/src/share/vm/opto/node.hpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/node.hpp	Thu Mar 13 16:06:34 2008 -0700
@@ -106,6 +106,7 @@
 class RegionNode;
 class RootNode;
 class SafePointNode;
+class SafePointScalarObjectNode;
 class StartNode;
 class State;
 class StoreNode;
@@ -575,6 +576,7 @@
       DEFINE_CLASS_ID(ConstraintCast, Type, 1)
       DEFINE_CLASS_ID(CheckCastPP, Type, 2)
       DEFINE_CLASS_ID(CMove, Type, 3)
+      DEFINE_CLASS_ID(SafePointScalarObject, Type, 4)
 
     DEFINE_CLASS_ID(Mem,   Node, 6)
       DEFINE_CLASS_ID(Load,  Mem, 0)
@@ -721,6 +723,7 @@
   DEFINE_CLASS_QUERY(Region)
   DEFINE_CLASS_QUERY(Root)
   DEFINE_CLASS_QUERY(SafePoint)
+  DEFINE_CLASS_QUERY(SafePointScalarObject)
   DEFINE_CLASS_QUERY(Start)
   DEFINE_CLASS_QUERY(Store)
   DEFINE_CLASS_QUERY(Sub)
--- a/src/share/vm/opto/output.cpp	Thu Mar 13 05:40:44 2008 -0700
+++ b/src/share/vm/opto/output.cpp	Thu Mar 13 16:06:34 2008 -0700
@@ -561,7 +561,30 @@
     : new LocationValue(Location::new_stk_loc(l_type,  ra->reg2offset(regnum)));
 }
 
-void Compile::FillLocArray( int idx, Node *local, GrowableArray<ScopeValue*> *array ) {
+
+ObjectValue*
+Compile::sv_for_node_id(GrowableArray<ScopeValue*> *objs, int id) {
+  for (int i = 0; i < objs->length(); i++) {
+    assert(objs->at(i)->is_object(), "corrupt object cache");
+    ObjectValue* sv = (ObjectValue*) objs->at(i);
+    if (sv->id() == id) {
+      return sv;
+    }
+  }
+  // Otherwise..
+  return NULL;
+}
+
+void Compile::set_sv_for_object_node(GrowableArray<ScopeValue*> *objs,
+                                     ObjectValue* sv ) {
+  assert(sv_for_node_id(objs, sv->id()) == NULL, "Precondition");
+  objs->append(sv);
+}
+
+
+void Compile::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local,
+                            GrowableArray<ScopeValue*> *array,
+                            GrowableArray<ScopeValue*> *objs ) {
   assert( local, "use _top instead of null" );
   if (array->length() != idx) {
     assert(array->length() == idx + 1, "Unexpected array count");
@@ -578,6 +601,29 @@
   }
   const Type *t = local->bottom_type();
 
+  // Is it a safepoint scalar object node?
+  if (local->is_SafePointScalarObject()) {
+    SafePointScalarObjectNode* spobj = local->as_SafePointScalarObject();
+
+    ObjectValue* sv = Compile::sv_for_node_id(objs, spobj->_idx);
+    if (sv == NULL) {
+      ciKlass* cik = t->is_oopptr()->klass();
+      assert(cik->is_instance_klass() ||
+             cik->is_array_klass(), "Not supported allocation.");
+      sv = new ObjectValue(spobj->_idx,
+                           new ConstantOopWriteValue(cik->encoding()));
+      Compile::set_sv_for_object_node(objs, sv);
+
+      uint first_ind = spobj->first_index();
+      for (uint i = 0; i < spobj->n_fields(); i++) {
+        Node* fld_node = sfpt->in(first_ind+i);
+        (void)FillLocArray(sv->field_values()->length(), sfpt, fld_node, sv->field_values(), objs);
+      }
+    }
+    array->append(sv);
+    return;
+  }
+
   // Grab the register number for the local
   OptoReg::Name regnum = _regalloc->get_reg_first(local);
   if( OptoReg::is_valid(regnum) ) {// Got a register/stack?
@@ -755,6 +801,11 @@
   JVMState* youngest_jvms = sfn->jvms();
   int max_depth = youngest_jvms->depth();
 
+  // Allocate the object pool for scalar-replaced objects -- the map from
+  // small-integer keys (which can be recorded in the local and ostack
+  // arrays) to descriptions of the object state.
+  GrowableArray<ScopeValue*> *objs = new GrowableArray<ScopeValue*>();
+
   // Visit scopes from oldest to youngest.
   for (int depth = 1; depth <= max_depth; depth++) {
     JVMState* jvms = youngest_jvms->of_depth(depth);
@@ -773,13 +824,13 @@
     // Insert locals into the locarray
     GrowableArray<ScopeValue*> *locarray = new GrowableArray<ScopeValue*>(num_locs);
     for( idx = 0; idx < num_locs; idx++ ) {
-      FillLocArray( idx, sfn->local(jvms, idx), locarray );
+      FillLocArray( idx, sfn, sfn->local(jvms, idx), locarray, objs );
     }
 
     // Insert expression stack entries into the exparray
     GrowableArray<ScopeValue*> *exparray = new GrowableArray<ScopeValue*>(num_exps);
     for( idx = 0; idx < num_exps; idx++ ) {
-      FillLocArray( idx,  sfn->stack(jvms, idx), exparray );
+      FillLocArray( idx,  sfn, sfn->stack(jvms, idx), exparray, objs );
     }
 
     // Add in mappings of the monitors
@@ -803,7 +854,27 @@
 
       // Create ScopeValue for object
       ScopeValue *scval = NULL;
-      if( !obj_node->is_Con() ) {
+
+      if( obj_node->is_SafePointScalarObject() ) {
+        SafePointScalarObjectNode* spobj = obj_node->as_SafePointScalarObject();
+        scval = Compile::sv_for_node_id(objs, spobj->_idx);
+        if (scval == NULL) {
+          const Type *t = obj_node->bottom_type();
+          ciKlass* cik = t->is_oopptr()->klass();
+          assert(cik->is_instance_klass() ||
+                 cik->is_array_klass(), "Not supported allocation.");
+          ObjectValue* sv = new ObjectValue(spobj->_idx,
+                                new ConstantOopWriteValue(cik->encoding()));
+          Compile::set_sv_for_object_node(objs, sv);
+
+          uint first_ind = spobj->first_index();
+          for (uint i = 0; i < spobj->n_fields(); i++) {
+            Node* fld_node = sfn->in(first_ind+i);
+            (void)FillLocArray(sv->field_values()->length(), sfn, fld_node, sv->field_values(), objs);
+          }
+          scval = sv;
+        }
+      } else if( !obj_node->is_Con() ) {
         OptoReg::Name obj_reg = _regalloc->get_reg_first(obj_node);
         scval = new_loc_value( _regalloc, obj_reg, Location::oop );
       } else {
@@ -814,6 +885,9 @@
       monarray->append(new MonitorValue(scval, Location::new_stk_loc(Location::normal,_regalloc->reg2offset(box_reg))));
     }
 
+    // We dump the object pool first, since deoptimization reads it in first.
+    debug_info()->dump_object_pool(objs);
+
     // Build first class objects to pass to scope
     DebugToken *locvals = debug_info()->create_scope_values(locarray);
     DebugToken *expvals = debug_info()->create_scope_values(exparray);
@@ -823,6 +897,7 @@
     ciMethod* scope_method = method ? method : _method;
     // Describe the scope here
     assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI");
+    // Now we can describe the scope.
     debug_info()->describe_scope(safepoint_pc_offset,scope_method,jvms->bci(),locvals,expvals,monvals);
   } // End jvms loop