changeset 10953:97e282186b5b

Add heap sanity checker with premature hard crash for debugging write barriers
author Christos Kotselidis <christos.kotselidis@oracle.com>
date Fri, 02 Aug 2013 19:03:05 +0200
parents b43bc053ce8f
children d348dd117239
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java src/share/vm/graal/graalCompilerToVM.cpp src/share/vm/graal/graalRuntime.cpp src/share/vm/graal/graalRuntime.hpp
diffstat 6 files changed, 40 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Aug 02 18:29:49 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Aug 02 19:03:05 2013 +0200
@@ -506,6 +506,7 @@
     public long vmErrorAddress;
     public long writeBarrierPreAddress;
     public long writeBarrierPostAddress;
+    public long validateObject;
     public long javaTimeMillisAddress;
     public long javaTimeNanosAddress;
     public long arithmeticSinAddress;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Aug 02 18:29:49 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Aug 02 19:03:05 2013 +0200
@@ -311,6 +311,8 @@
         linkForeignCall(r, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, LEAF, NOT_REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(r, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(r, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        linkForeignCall(r, VALIDATEOBJECT, c.validateObject, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
+
         if (IntrinsifyObjectMethods.getValue()) {
             r.registerSubstitutions(ObjectSubstitutions.class);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Fri Aug 02 18:29:49 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Fri Aug 02 19:03:05 2013 +0200
@@ -160,6 +160,7 @@
         Object fixedValue = FixedValueAnchorNode.getObject(value);
         verifyOop(fixedObject);
         verifyOop(fixedValue);
+        validateObject(fixedObject, fixedValue);
         Word oop;
         if (usePrecise) {
             oop = (Word) Word.fromArray(fixedObject, location);
@@ -409,4 +410,23 @@
     private static boolean traceBarrier() {
         return GraalOptions.GCDebugStartCycle.getValue() > 0 && ((int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress()).readLong(0) > GraalOptions.GCDebugStartCycle.getValue());
     }
+
+    /**
+     * Validation helper method which performs sanity checks on write operations. The addresses of
+     * both the object and the value being written are checked in order to determine if they reside
+     * in a valid heap region. If an object is stale, an invalid access is performed in order to
+     * prematurely crash the VM and debug the stack trace of the faulty method.
+     */
+    private static void validateObject(Object parent, Object child) {
+        if (child != null && !validateOop(VALIDATEOBJECT, parent, child)) {
+            log(true, "Verification ERROR, Parent: %p Child: %p\n", Word.fromObject(parent).rawValue(), Word.fromObject(child).rawValue());
+            DirectObjectStoreNode.storeWord(null, 0, 0, Word.zero());
+        }
+    }
+
+    public static final ForeignCallDescriptor VALIDATEOBJECT = new ForeignCallDescriptor("validate_object", boolean.class, Word.class, Word.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native boolean validateOop(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object parent, Object object);
+
 }
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Aug 02 18:29:49 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri Aug 02 19:03:05 2013 +0200
@@ -859,6 +859,7 @@
   set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre);
   set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post);
   set_address("gcTotalCollectionsAddress", (jlong)(address)(Universe::heap()->total_collections_address()));
+  set_address("validateObject", GraalRuntime::validate_object);
 
   BarrierSet* bs = Universe::heap()->barrier_set();
   switch (bs->kind()) {
--- a/src/share/vm/graal/graalRuntime.cpp	Fri Aug 02 18:29:49 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Fri Aug 02 19:03:05 2013 +0200
@@ -372,6 +372,21 @@
   thread->dirty_card_queue().enqueue(card_addr);
 JRT_END
 
+JRT_LEAF(jboolean, GraalRuntime::validate_object(JavaThread* thread,oopDesc* parent, oopDesc* child))
+  bool ret = true;
+  if(!Universe::heap()->is_in_closed_subset(parent)) {
+    tty->print_cr("Parent Object "INTPTR_FORMAT" not in heap", parent);
+    parent->print();
+    ret=false;
+  }
+  if(!Universe::heap()->is_in_closed_subset(child)) {
+    tty->print_cr("Child Object "INTPTR_FORMAT" not in heap", child);
+    child->print();
+    ret=false;
+  }
+  return (jint)ret;
+JRT_END
+
 JRT_ENTRY(void, GraalRuntime::vm_error(JavaThread* thread, oop where, oop format, jlong value))
   ResourceMark rm;
   assert(where == NULL || java_lang_String::is_instance(where), "must be");
--- a/src/share/vm/graal/graalRuntime.hpp	Fri Aug 02 18:29:49 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Fri Aug 02 19:03:05 2013 +0200
@@ -55,6 +55,7 @@
   static void log_object(JavaThread* thread, oop msg, jint flags);
   static void write_barrier_pre(JavaThread* thread, oopDesc* obj);
   static void write_barrier_post(JavaThread* thread, void* card);
+  static jboolean validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child);
 };
 
 #endif // SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP