8192004: InspectedFrame.materializeVirtualObjects only updates locals with new objects
authornever
Thu, 18 Jan 2018 09:01:00 -0800
changeset 48792 d2920683b2ea
parent 48791 6e079ff6c83c
child 48793 b9a29dfaaeb2
8192004: InspectedFrame.materializeVirtualObjects only updates locals with new objects Reviewed-by: kvn, sspitsyn, phh
src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
src/hotspot/share/runtime/vframe_hp.cpp
src/hotspot/share/runtime/vframe_hp.hpp
--- 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<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 @@
         }
       }
     }
+
+    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
--- 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<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();
-        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<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 @@
     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 @@
   // 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 @@
                                    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() {
-  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<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());
     }
   }
 }
--- 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<mtCompiler> {
+  friend class compiledVFrame;
+
 private:
 
   Method* _method;
@@ -99,17 +109,23 @@
   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);