aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkvn <none@none>2008-03-13 16:06:34 -0700
committerkvn <none@none>2008-03-13 16:06:34 -0700
commitae1e5eeb2c723b80415eb94785093830e1695f9e (patch)
tree50e52b89087c4310694b4986570b12e9e2c363a7
parent0faf1a4d124c7b728bc59d791f79d993a36ade9b (diff)
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
-rw-r--r--src/share/vm/opto/callnode.cpp161
-rw-r--r--src/share/vm/opto/callnode.hpp58
-rw-r--r--src/share/vm/opto/classes.hpp1
-rw-r--r--src/share/vm/opto/compile.hpp16
-rw-r--r--src/share/vm/opto/graphKit.cpp8
-rw-r--r--src/share/vm/opto/macro.cpp17
-rw-r--r--src/share/vm/opto/matcher.cpp1
-rw-r--r--src/share/vm/opto/node.hpp3
-rw-r--r--src/share/vm/opto/output.cpp83
9 files changed, 322 insertions, 26 deletions
diff --git a/src/share/vm/opto/callnode.cpp b/src/share/vm/opto/callnode.cpp
index f32562de0..b0bcf4ee8 100644
--- a/src/share/vm/opto/callnode.cpp
+++ b/src/share/vm/opto/callnode.cpp
@@ -230,6 +230,7 @@ JVMState::JVMState(ciMethod* method, JVMState* caller) {
_locoff = TypeFunc::Parms;
_stkoff = _locoff + _method->max_locals();
_monoff = _stkoff + _method->max_stack();
+ _scloff = _monoff;
_endoff = _monoff;
_sp = 0;
}
@@ -242,6 +243,7 @@ JVMState::JVMState(int stack_size) {
_locoff = TypeFunc::Parms;
_stkoff = _locoff;
_monoff = _stkoff + stack_size;
+ _scloff = _monoff;
_endoff = _monoff;
_sp = 0;
}
@@ -297,12 +299,22 @@ uint JVMState::debug_depth() const {
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 @@ static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, c
}
}
}
-#endif
//------------------------------format-----------------------------------------
-#ifndef PRODUCT
void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const {
st->print(" #");
if( _method ) {
@@ -356,24 +366,25 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
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 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
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 @@ void JVMState::dump_spec(outputStream *st) const {
}
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 @@ void JVMState::dump_on(outputStream* st) const {
}
_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 @@ JVMState* JVMState::clone_shallow(Compile* C) const {
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 @@ const RegMask &SafePointNode::out_RegMask() const {
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 @@ void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) {
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 @@ void SafePointNode::push_monitor(const FastLockNode *lock) {
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 @@ void SafePointNode::push_monitor(const FastLockNode *lock) {
add_req(NULL);
add_req(NULL);
}
+ jvms()->set_scloff(nextmon+MonitorEdges);
jvms()->set_endoff(req());
}
@@ -795,10 +866,13 @@ void SafePointNode::pop_monitor() {
// 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 @@ uint SafePointNode::match_edge(uint idx) const {
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); }
diff --git a/src/share/vm/opto/callnode.hpp b/src/share/vm/opto/callnode.hpp
index d07a4d78d..179ad06b0 100644
--- a/src/share/vm/opto/callnode.hpp
+++ b/src/share/vm/opto/callnode.hpp
@@ -184,6 +184,7 @@ private:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
#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.
diff --git a/src/share/vm/opto/classes.hpp b/src/share/vm/opto/classes.hpp
index 26eff2b4e..0c5f53ba3 100644
--- a/src/share/vm/opto/classes.hpp
+++ b/src/share/vm/opto/classes.hpp
@@ -185,6 +185,7 @@ macro(Root)
macro(RoundDouble)
macro(RoundFloat)
macro(SafePoint)
+macro(SafePointScalarObject)
macro(SCMemProj)
macro(SinD)
macro(SqrtD)
diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp
index a4e4c1401..419bc68be 100644
--- a/src/share/vm/opto/compile.hpp
+++ b/src/share/vm/opto/compile.hpp
@@ -606,8 +606,20 @@ class Compile : public Phase {
// 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);
diff --git a/src/share/vm/opto/graphKit.cpp b/src/share/vm/opto/graphKit.cpp
index 45471f29f..b7dc9e1ed 100644
--- a/src/share/vm/opto/graphKit.cpp
+++ b/src/share/vm/opto/graphKit.cpp
@@ -857,6 +857,13 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
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 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
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.
diff --git a/src/share/vm/opto/macro.cpp b/src/share/vm/opto/macro.cpp
index 9ba4bc3d4..4a8ffd107 100644
--- a/src/share/vm/opto/macro.cpp
+++ b/src/share/vm/opto/macro.cpp
@@ -54,15 +54,30 @@ void PhaseMacroExpand::copy_call_debug_info(CallNode *oldcall, CallNode * newcal
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);
}
}
diff --git a/src/share/vm/opto/matcher.cpp b/src/share/vm/opto/matcher.cpp
index a8d673a7f..7d9cd51ef 100644
--- a/src/share/vm/opto/matcher.cpp
+++ b/src/share/vm/opto/matcher.cpp
@@ -1647,6 +1647,7 @@ void Matcher::find_shared( Node *n ) {
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;
diff --git a/src/share/vm/opto/node.hpp b/src/share/vm/opto/node.hpp
index 881de4d21..ac35f9b4f 100644
--- a/src/share/vm/opto/node.hpp
+++ b/src/share/vm/opto/node.hpp
@@ -106,6 +106,7 @@ class RegMask;
class RegionNode;
class RootNode;
class SafePointNode;
+class SafePointScalarObjectNode;
class StartNode;
class State;
class StoreNode;
@@ -575,6 +576,7 @@ public:
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 @@ public:
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)
diff --git a/src/share/vm/opto/output.cpp b/src/share/vm/opto/output.cpp
index 690459e5f..3c06b135f 100644
--- a/src/share/vm/opto/output.cpp
+++ b/src/share/vm/opto/output.cpp
@@ -561,7 +561,30 @@ static LocationValue *new_loc_value( PhaseRegAlloc *ra, OptoReg::Name regnum, Lo
: 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 @@ void Compile::FillLocArray( int idx, Node *local, GrowableArray<ScopeValue*> *ar
}
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 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
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 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
// 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 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
// 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 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
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 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
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