# HG changeset patch # User kvn # Date 1205449594 25200 # Node ID eac007780a58e7da4d56f7ca32ad4fbdf10c99dd # Parent 8b6e4918764062b4e92c050a58fa2d32d3c00eb7 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 diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/callnode.cpp --- 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 *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 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<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); } diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/callnode.hpp --- 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. diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/classes.hpp --- 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) diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/compile.hpp --- 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 *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 *array, + GrowableArray *objs ); + + // If "objs" contains an ObjectValue whose id is "id", returns it, else NULL. + static ObjectValue* sv_for_node_id(GrowableArray *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 *objs, + ObjectValue* sv ); // Process an OopMap Element while emitting nodes void Process_OopMap_Node(MachNode *mach, int code_offset); diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/graphKit.cpp --- 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. diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/macro.cpp --- 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); } } diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/matcher.cpp --- 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; diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/node.hpp --- 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) diff -r 8b6e49187640 -r eac007780a58 src/share/vm/opto/output.cpp --- 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 *array ) { + +ObjectValue* +Compile::sv_for_node_id(GrowableArray *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 *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 *array, + GrowableArray *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 *objs = new GrowableArray(); + // 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 *locarray = new GrowableArray(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 *exparray = new GrowableArray(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