changeset 10648:8660a090c3e2

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 07 Jul 2013 23:32:05 +0200
parents 2ea604c4c6ec (current diff) cb2d97f002d4 (diff)
children ac8b195fd3aa
files
diffstat 11 files changed, 126 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Sun Jul 07 23:32:05 2013 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -630,10 +631,15 @@
                 new SafepointInsertionPhase().apply(graph);
                 new WriteBarrierAdditionPhase().apply(graph);
 
+                int barriers = 0;
                 // First, the total number of expected barriers is checked.
-                final int barriers = graph.getNodes(SerialWriteBarrier.class).count();
-                Assert.assertTrue(expectedBarriers == barriers);
-
+                if (((HotSpotRuntime) runtime()).config.useG1GC) {
+                    barriers = graph.getNodes(G1PreWriteBarrier.class).count() + graph.getNodes(G1PostWriteBarrier.class).count();
+                    Assert.assertTrue(expectedBarriers * 2 == barriers);
+                } else {
+                    barriers = graph.getNodes(SerialWriteBarrier.class).count();
+                    Assert.assertTrue(expectedBarriers == barriers);
+                }
                 // Iterate over all write nodes and remove barriers according to input indices.
                 NodeIteratorClosure<Boolean> closure = new NodeIteratorClosure<Boolean>() {
 
@@ -653,10 +659,10 @@
                                     }
                                 }
                             }
-                        } else if (node instanceof SerialWriteBarrier) {
+                        } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) {
                             // Remove flagged write barriers.
                             if (currentState) {
-                                graph.removeFixed(((SerialWriteBarrier) node));
+                                graph.removeFixed(((FixedWithNextNode) node));
                                 return false;
                             }
                         }
@@ -692,7 +698,7 @@
                 try {
                     ReentrantNodeIterator.apply(closure, graph.start(), false, null);
                     Debug.setConfig(Debug.fixedConfig(false, false, false, false, config.dumpHandlers(), config.output()));
-                    new WriteBarrierVerificationPhase().apply(graph);
+                    new WriteBarrierVerificationPhase(((HotSpotRuntime) runtime()).config.useG1GC).apply(graph);
                 } catch (AssertionError error) {
                     /*
                      * Catch assertion, test for expected one and re-throw in order to validate unit
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sun Jul 07 23:32:05 2013 +0200
@@ -50,6 +50,7 @@
     public boolean usePopCountInstruction;
     public boolean useAESIntrinsics;
     public boolean useG1GC;
+    public long gcTotalCollectionsAddress;
 
     // Compressed Oops related values.
     public boolean useCompressedOops;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Sun Jul 07 23:32:05 2013 +0200
@@ -1214,7 +1214,7 @@
 
         ret.getMidTier().appendPhase(new WriteBarrierAdditionPhase());
         if (VerifyPhases.getValue()) {
-            ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase());
+            ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config.useG1GC));
         }
 
         return ret;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Sun Jul 07 23:32:05 2013 +0200
@@ -41,12 +41,18 @@
  */
 public class WriteBarrierVerificationPhase extends Phase {
 
+    private final boolean useG1GC;
+
+    public WriteBarrierVerificationPhase(boolean useG1GC) {
+        this.useG1GC = useG1GC;
+    }
+
     @Override
     protected void run(StructuredGraph graph) {
         processWrites(graph);
     }
 
-    private static void processWrites(StructuredGraph graph) {
+    private void processWrites(StructuredGraph graph) {
         for (Node node : graph.getNodes()) {
             if (isObjectWrite(node)) {
                 validateWrite(node);
@@ -54,7 +60,7 @@
         }
     }
 
-    private static void validateWrite(Node write) {
+    private void validateWrite(Node write) {
         /*
          * The currently validated write is checked in order to discover if it has an appropriate
          * attached write barrier.
@@ -68,14 +74,25 @@
         while (iterator.hasNext()) {
             Node currentNode = iterator.next();
             assert !isSafepoint(currentNode) : "Write barrier must be present";
-            if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier(write, (SerialWriteBarrier) currentNode))) {
-                expandFrontier(frontier, currentNode);
+            if (useG1GC) {
+                if (!(currentNode instanceof G1PostWriteBarrier) || ((currentNode instanceof G1PostWriteBarrier) && !validateBarrier(write, (WriteBarrier) currentNode))) {
+                    expandFrontier(frontier, currentNode);
+                }
+            } else {
+                if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier(write, (WriteBarrier) currentNode))) {
+                    expandFrontier(frontier, currentNode);
+                }
             }
         }
     }
 
-    private static boolean hasAttachedBarrier(Node node) {
-        return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && validateBarrier(node, (SerialWriteBarrier) ((FixedWithNextNode) node).next());
+    private boolean hasAttachedBarrier(Node node) {
+        if (useG1GC) {
+            return ((FixedWithNextNode) node).next() instanceof G1PostWriteBarrier && ((FixedWithNextNode) node).predecessor() instanceof G1PreWriteBarrier &&
+                            validateBarrier(node, (G1PostWriteBarrier) ((FixedWithNextNode) node).next()) && validateBarrier(node, (G1PreWriteBarrier) ((FixedWithNextNode) node).predecessor());
+        } else {
+            return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && validateBarrier(node, (SerialWriteBarrier) ((FixedWithNextNode) node).next());
+        }
     }
 
     private static boolean isObjectWrite(Node node) {
@@ -103,7 +120,7 @@
         return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode);
     }
 
-    private static boolean validateBarrier(Node write, SerialWriteBarrier barrier) {
+    private static boolean validateBarrier(Node write, WriteBarrier barrier) {
         ValueNode writtenObject = null;
         LocationNode writtenLocation = null;
         if (write instanceof WriteNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Sun Jul 07 23:32:05 2013 +0200
@@ -692,4 +692,9 @@
     public static int verifiedEntryPointOffset() {
         return config().nmethodEntryOffset;
     }
+
+    @Fold
+    public static long gcTotalCollectionsAddress() {
+        return config().gcTotalCollectionsAddress;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sun Jul 07 23:32:05 2013 +0200
@@ -259,7 +259,7 @@
             args.addConst("size", size);
             args.add("hub", hub);
             args.add("prototypeMarkWord", type.prototypeMarkWord());
-            args.addConst("fillContents", newInstanceNode.fillContents());
+            args.addConst("fillContents", useG1GC() ? true : newInstanceNode.fillContents());
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
@@ -284,7 +284,7 @@
             args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
             args.addConst("headerSize", headerSize);
             args.addConst("log2ElementSize", log2ElementSize);
-            args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("fillContents", useG1GC() ? true : newArrayNode.fillContents());
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
@@ -295,7 +295,7 @@
             Arguments args = new Arguments(allocateArrayDynamic);
             args.add("elementType", newArrayNode.getElementType());
             args.add("length", newArrayNode.length());
-            args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("fillContents", useG1GC() ? true : newArrayNode.fillContents());
 
             SnippetTemplate template = template(args);
             template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Sun Jul 07 23:32:05 2013 +0200
@@ -54,7 +54,7 @@
     private static Object instanceClone(Object src, Word hub, int layoutHelper) {
         int instanceSize = layoutHelper;
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false);
+        Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, useG1GC() ? true : false);
 
         Pointer memory = Word.fromObject(result);
         for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) {
@@ -71,7 +71,7 @@
         int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize);
 
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false);
+        Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, useG1GC() ? true : false);
 
         Pointer memory = Word.fromObject(result);
         for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Sun Jul 07 23:32:05 2013 +0200
@@ -28,11 +28,13 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.Node.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
@@ -40,12 +42,14 @@
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
+import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*;
 
 public class WriteBarrierSnippets implements Snippets {
 
     private static final SnippetCounter.Group countersWriteBarriers = SnippetCounters.getValue() ? new SnippetCounter.Group("WriteBarriers") : null;
     private static final SnippetCounter serialFieldWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialFieldWriteBarrier", "Number of Serial Field Write Barriers");
     private static final SnippetCounter serialArrayWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialArrayWriteBarrier", "Number of Serial Array Write Barriers");
+    private static final int gcStartCycles = GraalOptions.GCDebugStartCycle.getValue();
 
     @Snippet
     public static void serialArrayWriteBarrier(Object obj, Object location, @ConstantParameter boolean usePrecise) {
@@ -85,19 +89,15 @@
         }
     }
 
-    /**
-     * Log method of debugging purposes.
-     */
-    static void log(boolean enabled, String format, WordBase value) {
-        if (enabled) {
-            Log.printf(format, value.rawValue());
+    @Snippet
+    public static void g1PreWriteBarrier(Object object, Object expectedObject, Object location, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck,
+                    @ConstantParameter boolean trace) {
+        if (nullCheck && object == null) {
+            DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
         }
-    }
-
-    @Snippet
-    public static void g1PreWriteBarrier(Object object, Object expectedObject, Object location, @ConstantParameter boolean doLoad) {
         Word thread = thread();
         Object fixedObject = FixedValueAnchorNode.getObject(object);
+        verifyOop(fixedObject);
         Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject);
         Word field = (Word) Word.fromArray(fixedObject, location);
         Word previousOop = (Word) Word.fromObject(fixedExpectedObject);
@@ -105,19 +105,33 @@
         Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset());
         Word indexAddress = thread.add(g1SATBQueueIndexOffset());
         Word indexValue = indexAddress.readWord(0);
-
+        int gcCycle = 0;
+        if (trace) {
+            gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress()).readLong(0);
+            log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.fromObject(fixedObject).rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.fromObject(fixedExpectedObject).rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue);
+            log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L);
+        }
         // If the concurrent marker is enabled, the barrier is issued.
-        if (markingValue != (byte) 0) {
+        if (probability(NOT_LIKELY_PROBABILITY, markingValue != (byte) 0)) {
             // If the previous value has to be loaded (before the write), the load is issued.
             // The load is always issued except the cases of CAS and referent field.
-            if (doLoad) {
+            if (probability(LIKELY_PROBABILITY, doLoad)) {
                 previousOop = (Word) Word.fromObject(field.readObjectCompressed(0));
+                if (trace) {
+                    if (previousOop.notEqual(Word.zero())) {
+                        verifyOop(previousOop.toObject());
+                    }
+                    log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue());
+                }
             }
             // If the previous value is null the barrier should not be issued.
-            if (previousOop.notEqual(0)) {
+            if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) {
                 // If the thread-local SATB buffer is full issue a native call which will
                 // initialize a new one and add the entry.
-                if (indexValue.notEqual(0)) {
+                if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
                     Word nextIndex = indexValue.subtract(wordSize());
                     Word logAddress = bufferAddress.add(nextIndex);
                     // Log the object to be marked as well as update the SATB's buffer next index.
@@ -131,10 +145,12 @@
     }
 
     @Snippet
-    public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise) {
+    public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise, @ConstantParameter boolean trace) {
         Word thread = thread();
         Object fixedObject = FixedValueAnchorNode.getObject(object);
         Object fixedValue = FixedValueAnchorNode.getObject(value);
+        verifyOop(fixedObject);
+        verifyOop(fixedValue);
         Word oop = (Word) Word.fromObject(fixedObject);
         Word field;
         if (usePrecise) {
@@ -142,7 +158,12 @@
         } else {
             field = oop;
         }
-
+        int gcCycle = 0;
+        if (trace) {
+            gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress()).readLong(0);
+            log(trace, "[%d] G1-Post Thread: %p Object: %p Field: %p\n", gcCycle, thread.rawValue(), Word.fromObject(fixedObject).rawValue());
+            log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), field.rawValue());
+        }
         Word writtenValue = (Word) Word.fromObject(fixedValue);
         Word bufferAddress = thread.readWord(g1CardQueueBufferOffset());
         Word indexAddress = thread.add(g1CardQueueIndexOffset());
@@ -163,16 +184,17 @@
         }
         Word cardAddress = cardBase.add(displacement);
 
-        if (xorResult.notEqual(0)) {
+        if (probability(LIKELY_PROBABILITY, xorResult.notEqual(0))) {
             // If the written value is not null continue with the barrier addition.
-            if (writtenValue.notEqual(0)) {
+            if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) {
                 byte cardByte = cardAddress.readByte(0);
                 // If the card is already dirty, (hence already enqueued) skip the insertion.
-                if (cardByte != (byte) 0) {
+                if (probability(LIKELY_PROBABILITY, cardByte != (byte) 0)) {
+                    log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), Word.unsigned(cardByte).rawValue());
                     cardAddress.writeByte(0, (byte) 0);
                     // If the thread local card queue is full, issue a native call which will
                     // initialize a new one and add the card entry.
-                    if (indexValue.notEqual(0)) {
+                    if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
                         Word nextIndex = indexValue.subtract(wordSize());
                         Word logAddress = bufferAddress.add(nextIndex);
                         // Log the object to be scanned as well as update
@@ -305,6 +327,8 @@
             args.add("expectedObject", writeBarrierPre.getExpectedObject());
             args.add("location", writeBarrierPre.getLocation());
             args.addConst("doLoad", writeBarrierPre.doLoad());
+            args.addConst("nullCheck", !writeBarrierPre.getObject().stamp().nonNull());
+            args.addConst("trace", traceBarrier());
             template(args).instantiate(runtime, writeBarrierPre, DEFAULT_REPLACER, args);
         }
 
@@ -314,6 +338,7 @@
             args.add("value", writeBarrierPost.getValue());
             args.add("location", writeBarrierPost.getLocation());
             args.addConst("usePrecise", writeBarrierPost.usePrecise());
+            args.addConst("trace", traceBarrier());
             template(args).instantiate(runtime, writeBarrierPost, DEFAULT_REPLACER, args);
         }
 
@@ -333,4 +358,29 @@
             template(args).instantiate(runtime, arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
     }
+
+    /**
+     * Log method of debugging purposes.
+     */
+    private static void log(boolean enabled, String format, long value) {
+        if (enabled) {
+            Log.printf(format, value);
+        }
+    }
+
+    private static void log(boolean enabled, String format, long value1, long value2) {
+        if (enabled) {
+            Log.printf(format, value1, value2);
+        }
+    }
+
+    private static void log(boolean enabled, String format, long value1, long value2, long value3) {
+        if (enabled) {
+            Log.printf(format, value1, value2, value3);
+        }
+    }
+
+    private static boolean traceBarrier() {
+        return gcStartCycles > 0 && ((int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress()).readLong(0) > gcStartCycles);
+    }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sun Jul 07 22:28:18 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sun Jul 07 23:32:05 2013 +0200
@@ -143,7 +143,8 @@
     // Debug settings:
     @Option(help = "")
     public static final OptionValue<Boolean> BootstrapReplacements = new OptionValue<>(false);
-
+    @Option(help = "")
+    public static final OptionValue<Integer> GCDebugStartCycle = new OptionValue<>(-1);
     // Ideal graph visualizer output settings
     @Option(help = "")
     public static final OptionValue<Boolean> PrintBinaryGraphs = new OptionValue<>(true);
--- a/src/share/vm/gc_interface/collectedHeap.hpp	Sun Jul 07 22:28:18 2013 +0200
+++ b/src/share/vm/gc_interface/collectedHeap.hpp	Sun Jul 07 23:32:05 2013 +0200
@@ -490,7 +490,9 @@
   // Total number of GC collections (started)
   unsigned int total_collections() const { return _total_collections; }
   unsigned int total_full_collections() const { return _total_full_collections;}
-
+#ifdef GRAAL
+  void* total_collections_address() { return &_total_collections;}
+#endif
   // Increment total number of GC collections (started)
   // Should be protected but used by PSMarkSweep - cleanup for 1.4.2
   void increment_total_collections(bool full = false) {
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Sun Jul 07 22:28:18 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Sun Jul 07 23:32:05 2013 +0200
@@ -907,6 +907,7 @@
   set_int("g1SATBQueueBufferOffset", in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_buf()));
   set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre);
   set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post);
+  set_address("gcTotalCollectionsAddress", (jlong)(address)(Universe::heap()->total_collections_address()));
 
   BarrierSet* bs = Universe::heap()->barrier_set();
   switch (bs->kind()) {