# HG changeset patch # User never # Date 1516294860 28800 # Node ID d2920683b2ea51b196c62a601d3dec7a6e90ac2a # Parent 6e079ff6c83c2e6146f59839ea529820e815023f 8192004: InspectedFrame.materializeVirtualObjects only updates locals with new objects Reviewed-by: kvn, sspitsyn, phh diff -r 6e079ff6c83c -r d2920683b2ea src/hotspot/share/jvmci/jvmciCompilerToVM.cpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Wed Jan 17 21:44:44 2018 -0800 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Thu Jan 18 09:01:00 2018 -0800 @@ -1660,7 +1660,6 @@ GrowableArray* 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 @@ } } } + + GrowableArray* 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* scopeMonitors = cvf->scope()->monitors(); + GrowableArray* 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 diff -r 6e079ff6c83c -r d2920683b2ea src/hotspot/share/runtime/vframe_hp.cpp --- a/src/hotspot/share/runtime/vframe_hp.cpp Wed Jan 17 21:44:44 2018 -0800 +++ b/src/hotspot/share/runtime/vframe_hp.cpp Thu Jan 18 09:01:00 2018 -0800 @@ -57,61 +57,19 @@ // 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* 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* 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(); - 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); + if (list->at(i)->matches(this)) { + list->at(i)->update_locals(result); 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(); } } } @@ -126,29 +84,32 @@ } 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* 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* 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 @@ deferred = new(ResourceObj::C_HEAP, mtCompiler) GrowableArray (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 @@ // 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* 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 @@ mv->eliminated(), false)); } } + + // Replace the original values with any stores that have been + // performed through compiledVFrame::update_monitors. + GrowableArray* 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() { - 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 @@ 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* 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()); } } } diff -r 6e079ff6c83c -r d2920683b2ea src/hotspot/share/runtime/vframe_hp.hpp --- a/src/hotspot/share/runtime/vframe_hp.hpp Wed Jan 17 21:44:44 2018 -0800 +++ b/src/hotspot/share/runtime/vframe_hp.hpp Thu Jan 18 09:01:00 2018 -0800 @@ -51,6 +51,8 @@ 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 @@ // 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 jvmtiDeferredLocalVariable; class jvmtiDeferredLocalVariableSet : public CHeapObj { + friend class compiledVFrame; + private: Method* _method; @@ -99,17 +109,23 @@ int _vframe_id; GrowableArray* _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* 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* monitors); // Does the vframe match this jvmtiDeferredLocalVariableSet - bool matches(vframe* vf); + bool matches(const vframe* vf); // GC void oops_do(OopClosure* f);