8192004: InspectedFrame.materializeVirtualObjects only updates locals with new objects

Reviewed-by: kvn, sspitsyn, phh
This commit is contained in:
Tom Rodriguez 2018-01-18 09:01:00 -08:00
parent 71a40bce38
commit 99725d3ea6
3 changed files with 184 additions and 87 deletions

View File

@ -1660,7 +1660,6 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame
GrowableArray<ScopeValue*>* scopeLocals = cvf->scope()->locals();
StackValueCollection* locals = cvf->locals();
if (locals != NULL) {
for (int i2 = 0; i2 < locals->size(); i2++) {
StackValue* var = locals->at(i2);
@ -1671,6 +1670,27 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame
}
}
}
GrowableArray<ScopeValue*>* scopeExpressions = cvf->scope()->expressions();
StackValueCollection* expressions = cvf->expressions();
if (expressions != NULL) {
for (int i2 = 0; i2 < expressions->size(); i2++) {
StackValue* var = expressions->at(i2);
if (var->type() == T_OBJECT && scopeExpressions->at(i2)->is_object()) {
jvalue val;
val.l = (jobject) expressions->at(i2)->get_obj()();
cvf->update_stack(T_OBJECT, i2, val);
}
}
}
GrowableArray<MonitorValue*>* scopeMonitors = cvf->scope()->monitors();
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
if (monitors != NULL) {
for (int i2 = 0; i2 < monitors->length(); i2++) {
cvf->update_monitor(i2, monitors->at(i2));
}
}
}
// all locals are materialized by now

View File

@ -57,65 +57,23 @@ StackValueCollection* compiledVFrame::locals() const {
// There is one scv_list entry for every JVM stack state in use.
int length = scv_list->length();
StackValueCollection* result = new StackValueCollection(length);
// In rare instances set_locals may have occurred in which case
// there are local values that are not described by the ScopeValue anymore
GrowableArray<jvmtiDeferredLocalVariable*>* deferred = NULL;
for (int i = 0; i < length; i++) {
result->add(create_stack_value(scv_list->at(i)));
}
// Replace the original values with any stores that have been
// performed through compiledVFrame::update_locals.
GrowableArray<jvmtiDeferredLocalVariableSet*>* list = thread()->deferred_locals();
if (list != NULL ) {
// In real life this never happens or is typically a single element search
for (int i = 0; i < list->length(); i++) {
if (list->at(i)->matches((vframe*)this)) {
deferred = list->at(i)->locals();
if (list->at(i)->matches(this)) {
list->at(i)->update_locals(result);
break;
}
}
}
for( int i = 0; i < length; i++ ) {
result->add( create_stack_value(scv_list->at(i)) );
}
// Replace specified locals with any deferred writes that are present
if (deferred != NULL) {
for ( int l = 0; l < deferred->length() ; l ++) {
jvmtiDeferredLocalVariable* val = deferred->at(l);
switch (val->type()) {
case T_BOOLEAN:
result->set_int_at(val->index(), val->value().z);
break;
case T_CHAR:
result->set_int_at(val->index(), val->value().c);
break;
case T_FLOAT:
result->set_float_at(val->index(), val->value().f);
break;
case T_DOUBLE:
result->set_double_at(val->index(), val->value().d);
break;
case T_BYTE:
result->set_int_at(val->index(), val->value().b);
break;
case T_SHORT:
result->set_int_at(val->index(), val->value().s);
break;
case T_INT:
result->set_int_at(val->index(), val->value().i);
break;
case T_LONG:
result->set_long_at(val->index(), val->value().j);
break;
case T_OBJECT:
{
Handle obj(Thread::current(), (oop)val->value().l);
result->set_obj_at(val->index(), obj);
}
break;
default:
ShouldNotReachHere();
}
}
}
return result;
}
@ -126,29 +84,32 @@ void compiledVFrame::set_locals(StackValueCollection* values) const {
}
void compiledVFrame::update_local(BasicType type, int index, jvalue value) {
assert(index >= 0 && index < method()->max_locals(), "out of bounds");
update_deferred_value(type, index, value);
}
#ifdef ASSERT
void compiledVFrame::update_stack(BasicType type, int index, jvalue value) {
assert(index >= 0 && index < method()->max_stack(), "out of bounds");
update_deferred_value(type, index + method()->max_locals(), value);
}
void compiledVFrame::update_monitor(int index, MonitorInfo* val) {
assert(index >= 0, "out of bounds");
jvalue value;
value.l = (jobject) val->owner();
update_deferred_value(T_OBJECT, index + method()->max_locals() + method()->max_stack(), value);
}
void compiledVFrame::update_deferred_value(BasicType type, int index, jvalue value) {
assert(fr().is_deoptimized_frame(), "frame must be scheduled for deoptimization");
#endif /* ASSERT */
GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred = thread()->deferred_locals();
jvmtiDeferredLocalVariableSet* locals = NULL;
if (deferred != NULL ) {
// See if this vframe has already had locals with deferred writes
int f;
for ( f = 0 ; f < deferred->length() ; f++ ) {
for (int f = 0; f < deferred->length(); f++ ) {
if (deferred->at(f)->matches(this)) {
// Matching, vframe now see if the local already had deferred write
GrowableArray<jvmtiDeferredLocalVariable*>* locals = deferred->at(f)->locals();
int l;
for (l = 0 ; l < locals->length() ; l++ ) {
if (locals->at(l)->index() == index) {
locals->at(l)->set_value(value);
return;
}
}
// No matching local already present. Push a new value onto the deferred collection
locals->push(new jvmtiDeferredLocalVariable(index, type, value));
return;
locals = deferred->at(f);
break;
}
}
// No matching vframe must push a new vframe
@ -158,9 +119,12 @@ void compiledVFrame::update_local(BasicType type, int index, jvalue value) {
deferred = new(ResourceObj::C_HEAP, mtCompiler) GrowableArray<jvmtiDeferredLocalVariableSet*> (1, true);
thread()->set_deferred_locals(deferred);
}
deferred->push(new jvmtiDeferredLocalVariableSet(method(), bci(), fr().id(), vframe_id()));
assert(deferred->top()->id() == fr().id(), "Huh? Must match");
deferred->top()->set_local_at(index, type, value);
if (locals == NULL) {
locals = new jvmtiDeferredLocalVariableSet(method(), bci(), fr().id(), vframe_id());
deferred->push(locals);
assert(locals->id() == fr().id(), "Huh? Must match");
}
locals->set_value_at(index, type, value);
}
StackValueCollection* compiledVFrame::expressions() const {
@ -173,8 +137,22 @@ StackValueCollection* compiledVFrame::expressions() const {
// There is one scv_list entry for every JVM stack state in use.
int length = scv_list->length();
StackValueCollection* result = new StackValueCollection(length);
for( int i = 0; i < length; i++ )
result->add( create_stack_value(scv_list->at(i)) );
for (int i = 0; i < length; i++) {
result->add(create_stack_value(scv_list->at(i)));
}
// Replace the original values with any stores that have been
// performed through compiledVFrame::update_stack.
GrowableArray<jvmtiDeferredLocalVariableSet*>* list = thread()->deferred_locals();
if (list != NULL ) {
// In real life this never happens or is typically a single element search
for (int i = 0; i < list->length(); i++) {
if (list->at(i)->matches(this)) {
list->at(i)->update_stack(result);
break;
}
}
}
return result;
}
@ -236,6 +214,20 @@ GrowableArray<MonitorInfo*>* compiledVFrame::monitors() const {
mv->eliminated(), false));
}
}
// Replace the original values with any stores that have been
// performed through compiledVFrame::update_monitors.
GrowableArray<jvmtiDeferredLocalVariableSet*>* list = thread()->deferred_locals();
if (list != NULL ) {
// In real life this never happens or is typically a single element search
for (int i = 0; i < list->length(); i++) {
if (list->at(i)->matches(this)) {
list->at(i)->update_monitors(result);
break;
}
}
}
return result;
}
@ -332,14 +324,14 @@ jvmtiDeferredLocalVariableSet::jvmtiDeferredLocalVariableSet(Method* method, int
}
jvmtiDeferredLocalVariableSet::~jvmtiDeferredLocalVariableSet() {
for (int i = 0; i < _locals->length() ; i++ ) {
for (int i = 0; i < _locals->length(); i++ ) {
delete _locals->at(i);
}
// Free growableArray and c heap for elements
delete _locals;
}
bool jvmtiDeferredLocalVariableSet::matches(vframe* vf) {
bool jvmtiDeferredLocalVariableSet::matches(const vframe* vf) {
if (!vf->is_compiled_frame()) return false;
compiledVFrame* cvf = (compiledVFrame*)vf;
if (cvf->fr().id() == id() && cvf->vframe_id() == vframe_id()) {
@ -349,24 +341,93 @@ bool jvmtiDeferredLocalVariableSet::matches(vframe* vf) {
return false;
}
void jvmtiDeferredLocalVariableSet::set_local_at(int idx, BasicType type, jvalue val) {
int i;
for ( i = 0 ; i < locals()->length() ; i++ ) {
if ( locals()->at(i)->index() == idx) {
assert(locals()->at(i)->type() == type, "Wrong type");
locals()->at(i)->set_value(val);
void jvmtiDeferredLocalVariableSet::set_value_at(int idx, BasicType type, jvalue val) {
for (int i = 0; i < _locals->length(); i++) {
if (_locals->at(i)->index() == idx) {
assert(_locals->at(i)->type() == type, "Wrong type");
_locals->at(i)->set_value(val);
return;
}
}
locals()->push(new jvmtiDeferredLocalVariable(idx, type, val));
_locals->push(new jvmtiDeferredLocalVariable(idx, type, val));
}
void jvmtiDeferredLocalVariableSet::update_value(StackValueCollection* locals, BasicType type, int index, jvalue value) {
switch (type) {
case T_BOOLEAN:
locals->set_int_at(index, value.z);
break;
case T_CHAR:
locals->set_int_at(index, value.c);
break;
case T_FLOAT:
locals->set_float_at(index, value.f);
break;
case T_DOUBLE:
locals->set_double_at(index, value.d);
break;
case T_BYTE:
locals->set_int_at(index, value.b);
break;
case T_SHORT:
locals->set_int_at(index, value.s);
break;
case T_INT:
locals->set_int_at(index, value.i);
break;
case T_LONG:
locals->set_long_at(index, value.j);
break;
case T_OBJECT:
{
Handle obj(Thread::current(), (oop)value.l);
locals->set_obj_at(index, obj);
}
break;
default:
ShouldNotReachHere();
}
}
void jvmtiDeferredLocalVariableSet::update_locals(StackValueCollection* locals) {
for (int l = 0; l < _locals->length(); l ++) {
jvmtiDeferredLocalVariable* val = _locals->at(l);
if (val->index() >= 0 && val->index() < method()->max_locals()) {
update_value(locals, val->type(), val->index(), val->value());
}
}
}
void jvmtiDeferredLocalVariableSet::update_stack(StackValueCollection* expressions) {
for (int l = 0; l < _locals->length(); l ++) {
jvmtiDeferredLocalVariable* val = _locals->at(l);
if (val->index() >= method()->max_locals() && val->index() < method()->max_locals() + method()->max_stack()) {
update_value(expressions, val->type(), val->index() - method()->max_locals(), val->value());
}
}
}
void jvmtiDeferredLocalVariableSet::update_monitors(GrowableArray<MonitorInfo*>* monitors) {
for (int l = 0; l < _locals->length(); l ++) {
jvmtiDeferredLocalVariable* val = _locals->at(l);
if (val->index() >= method()->max_locals() + method()->max_stack()) {
int lock_index = val->index() - (method()->max_locals() + method()->max_stack());
MonitorInfo* info = monitors->at(lock_index);
MonitorInfo* new_info = new MonitorInfo((oopDesc*)val->value().l, info->lock(), info->eliminated(), info->owner_is_scalar_replaced());
monitors->at_put(lock_index, new_info);
}
}
}
void jvmtiDeferredLocalVariableSet::oops_do(OopClosure* f) {
// The Method* is on the stack so a live activation keeps it alive
// either by mirror in interpreter or code in compiled code.
for ( int i = 0; i < locals()->length(); i++ ) {
if ( locals()->at(i)->type() == T_OBJECT) {
f->do_oop(locals()->at(i)->oop_addr());
for (int i = 0; i < _locals->length(); i++) {
if (_locals->at(i)->type() == T_OBJECT) {
f->do_oop(_locals->at(i)->oop_addr());
}
}
}

View File

@ -51,6 +51,8 @@ class compiledVFrame: public javaVFrame {
return (compiledVFrame*) vf;
}
void update_deferred_value(BasicType type, int index, jvalue value);
public:
// Constructors
compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, CompiledMethod* nm);
@ -58,6 +60,12 @@ class compiledVFrame: public javaVFrame {
// Update a local in a compiled frame. Update happens when deopt occurs
void update_local(BasicType type, int index, jvalue value);
// Update an expression stack value in a compiled frame. Update happens when deopt occurs
void update_stack(BasicType type, int index, jvalue value);
// Update a lock value in a compiled frame. Update happens when deopt occurs
void update_monitor(int index, MonitorInfo* value);
// Returns the active nmethod
CompiledMethod* code() const;
@ -91,6 +99,8 @@ class compiledVFrame: public javaVFrame {
class jvmtiDeferredLocalVariable;
class jvmtiDeferredLocalVariableSet : public CHeapObj<mtCompiler> {
friend class compiledVFrame;
private:
Method* _method;
@ -99,17 +109,23 @@ private:
int _vframe_id;
GrowableArray<jvmtiDeferredLocalVariable*>* _locals;
void update_value(StackValueCollection* locals, BasicType type, int index, jvalue value);
void set_value_at(int idx, BasicType typ, jvalue val);
public:
// JVM state
Method* method() const { return _method; }
int bci() const { return _bci; }
intptr_t* id() const { return _id; }
int vframe_id() const { return _vframe_id; }
GrowableArray<jvmtiDeferredLocalVariable*>* locals() const { return _locals; }
void set_local_at(int idx, BasicType typ, jvalue val);
void update_locals(StackValueCollection* locals);
void update_stack(StackValueCollection* locals);
void update_monitors(GrowableArray<MonitorInfo*>* monitors);
// Does the vframe match this jvmtiDeferredLocalVariableSet
bool matches(vframe* vf);
bool matches(const vframe* vf);
// GC
void oops_do(OopClosure* f);