6671807: (Escape Analysis) Add new ideal node to represent the state of a scalarized object at a safepoint
Values of non-static fields of a scalarized object should be saved in debug info to reallocate the object during deoptimization. Reviewed-by: never
This commit is contained in:
parent
1931e94bad
commit
000ac830a0
@ -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); }
|
||||
|
||||
|
@ -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.
|
||||
|
@ -185,6 +185,7 @@ macro(Root)
|
||||
macro(RoundDouble)
|
||||
macro(RoundFloat)
|
||||
macro(SafePoint)
|
||||
macro(SafePointScalarObject)
|
||||
macro(SCMemProj)
|
||||
macro(SinD)
|
||||
macro(SqrtD)
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user