6993125: runThese crashes with assert(Thread::current()->on_local_stack((address)this))
authorkvn
Fri, 10 Dec 2010 14:14:02 -0800
changeset 7440 eabaf35910a1
parent 7439 572e3f624901
child 7441 47ea904dba6a
6993125: runThese crashes with assert(Thread::current()->on_local_stack((address)this)) Summary: add another ResourceObj debug field to distinguish garbage Reviewed-by: dholmes, coleenp
hotspot/src/share/vm/asm/codeBuffer.cpp
hotspot/src/share/vm/memory/allocation.cpp
hotspot/src/share/vm/memory/allocation.hpp
--- a/hotspot/src/share/vm/asm/codeBuffer.cpp	Wed Dec 08 17:50:49 2010 -0800
+++ b/hotspot/src/share/vm/asm/codeBuffer.cpp	Fri Dec 10 14:14:02 2010 -0800
@@ -131,6 +131,7 @@
 #ifdef ASSERT
   // Save allocation type to execute assert in ~ResourceObj()
   // which is called after this destructor.
+  assert(_default_oop_recorder.allocated_on_stack(), "should be embedded object");
   ResourceObj::allocation_type at = _default_oop_recorder.get_allocation_type();
   Copy::fill_to_bytes(this, sizeof(*this), badResourceValue);
   ResourceObj::set_allocation_type((address)(&_default_oop_recorder), at);
--- a/hotspot/src/share/vm/memory/allocation.cpp	Wed Dec 08 17:50:49 2010 -0800
+++ b/hotspot/src/share/vm/memory/allocation.cpp	Fri Dec 10 14:14:02 2010 -0800
@@ -73,7 +73,7 @@
 void ResourceObj::operator delete(void* p) {
   assert(((ResourceObj *)p)->allocated_on_C_heap(),
          "delete only allowed for C_HEAP objects");
-  DEBUG_ONLY(((ResourceObj *)p)->_allocation = (uintptr_t)badHeapOopVal;)
+  DEBUG_ONLY(((ResourceObj *)p)->_allocation_t[0] = (uintptr_t)badHeapOopVal;)
   FreeHeap(p);
 }
 
@@ -83,43 +83,73 @@
     uintptr_t allocation = (uintptr_t)res;
     assert((allocation & allocation_mask) == 0, "address should be aligned to 4 bytes at least");
     assert(type <= allocation_mask, "incorrect allocation type");
-    ((ResourceObj *)res)->_allocation = ~(allocation + type);
+    ResourceObj* resobj = (ResourceObj *)res;
+    resobj->_allocation_t[0] = ~(allocation + type);
+    if (type != STACK_OR_EMBEDDED) {
+      // Called from operator new() and CollectionSetChooser(),
+      // set verification value.
+      resobj->_allocation_t[1] = (uintptr_t)&(resobj->_allocation_t[1]) + type;
+    }
 }
 
 ResourceObj::allocation_type ResourceObj::get_allocation_type() const {
-    assert(~(_allocation | allocation_mask) == (uintptr_t)this, "lost resource object");
-    return (allocation_type)((~_allocation) & allocation_mask);
+    assert(~(_allocation_t[0] | allocation_mask) == (uintptr_t)this, "lost resource object");
+    return (allocation_type)((~_allocation_t[0]) & allocation_mask);
+}
+
+bool ResourceObj::is_type_set() const {
+    allocation_type type = (allocation_type)(_allocation_t[1] & allocation_mask);
+    return get_allocation_type()  == type &&
+           (_allocation_t[1] - type) == (uintptr_t)(&_allocation_t[1]);
 }
 
 ResourceObj::ResourceObj() { // default constructor
-    if (~(_allocation | allocation_mask) != (uintptr_t)this) {
+    if (~(_allocation_t[0] | allocation_mask) != (uintptr_t)this) {
+      // Operator new() is not called for allocations
+      // on stack and for embedded objects.
       set_allocation_type((address)this, STACK_OR_EMBEDDED);
-    } else if (allocated_on_stack()) {
-      // For some reason we got a value which looks like an allocation on stack.
-      // Pass if it is really allocated on stack.
-      assert(Thread::current()->on_local_stack((address)this),"should be on stack");
+    } else if (allocated_on_stack()) { // STACK_OR_EMBEDDED
+      // For some reason we got a value which resembles
+      // an embedded or stack object (operator new() does not
+      // set such type). Keep it since it is valid value
+      // (even if it was garbage).
+      // Ignore garbage in other fields.
+    } else if (is_type_set()) {
+      // Operator new() was called and type was set.
+      assert(!allocated_on_stack(),
+             err_msg("not embedded or stack, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")",
+                     this, get_allocation_type(), _allocation_t[0], _allocation_t[1]));
     } else {
-      assert(allocated_on_res_area() || allocated_on_C_heap() || allocated_on_arena(),
-             "allocation_type should be set by operator new()");
+      // Operator new() was not called.
+      // Assume that it is embedded or stack object.
+      set_allocation_type((address)this, STACK_OR_EMBEDDED);
     }
+    _allocation_t[1] = 0; // Zap verification value
 }
 
 ResourceObj::ResourceObj(const ResourceObj& r) { // default copy constructor
     // Used in ClassFileParser::parse_constant_pool_entries() for ClassFileStream.
+    // Note: garbage may resembles valid value.
+    assert(~(_allocation_t[0] | allocation_mask) != (uintptr_t)this || !is_type_set(),
+           err_msg("embedded or stack only, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")",
+                   this, get_allocation_type(), _allocation_t[0], _allocation_t[1]));
     set_allocation_type((address)this, STACK_OR_EMBEDDED);
+    _allocation_t[1] = 0; // Zap verification value
 }
 
 ResourceObj& ResourceObj::operator=(const ResourceObj& r) { // default copy assignment
     // Used in InlineTree::ok_to_inline() for WarmCallInfo.
-    assert(allocated_on_stack(), "copy only into local");
-    // Keep current _allocation value;
+    assert(allocated_on_stack(),
+           err_msg("copy only into local, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")",
+                   this, get_allocation_type(), _allocation_t[0], _allocation_t[1]));
+    // Keep current _allocation_t value;
     return *this;
 }
 
 ResourceObj::~ResourceObj() {
     // allocated_on_C_heap() also checks that encoded (in _allocation) address == this.
-    if (!allocated_on_C_heap()) {  // ResourceObj::delete() zaps _allocation for C_heap.
-      _allocation = (uintptr_t)badHeapOopVal; // zap type
+    if (!allocated_on_C_heap()) { // ResourceObj::delete() will zap _allocation for C_heap.
+      _allocation_t[0] = (uintptr_t)badHeapOopVal; // zap type
     }
 }
 #endif // ASSERT
--- a/hotspot/src/share/vm/memory/allocation.hpp	Wed Dec 08 17:50:49 2010 -0800
+++ b/hotspot/src/share/vm/memory/allocation.hpp	Fri Dec 10 14:14:02 2010 -0800
@@ -337,7 +337,9 @@
   // When this object is allocated on stack the new() operator is not
   // called but garbage on stack may look like a valid allocation_type.
   // Store negated 'this' pointer when new() is called to distinguish cases.
-  uintptr_t _allocation;
+  // Use second array's element for verification value to distinguish garbage.
+  uintptr_t _allocation_t[2];
+  bool is_type_set() const;
  public:
   allocation_type get_allocation_type() const;
   bool allocated_on_stack()    const { return get_allocation_type() == STACK_OR_EMBEDDED; }