|
11 | 11 |
|
12 | 12 | import java.lang.management.GarbageCollectorMXBean;
|
13 | 13 | import java.lang.management.ManagementFactory;
|
| 14 | +import java.time.Duration; |
14 | 15 |
|
15 | 16 | import org.truffleruby.SuppressFBWarnings;
|
16 | 17 | import org.truffleruby.builtins.CoreMethod;
|
|
23 | 24 | import org.truffleruby.builtins.PrimitiveArrayArgumentsNode;
|
24 | 25 | import org.truffleruby.collections.WeakValueCache;
|
25 | 26 | import org.truffleruby.language.SafepointManager;
|
| 27 | +import org.truffleruby.language.control.RaiseException; |
26 | 28 |
|
27 | 29 | @CoreModule("GC")
|
28 | 30 | public abstract class GCNodes {
|
@@ -52,27 +54,45 @@ protected Object vmGCStart() {
|
52 | 54 | @Primitive(name = "gc_force")
|
53 | 55 | public static abstract class GCForce extends PrimitiveArrayArgumentsNode {
|
54 | 56 |
|
55 |
| - @SuppressFBWarnings("DLS") |
56 | 57 | @TruffleBoundary
|
57 | 58 | @Specialization
|
58 | 59 | protected Object force() {
|
59 | 60 | getContext().getMarkingService().queueMarking();
|
60 |
| - Object key = new Object(); |
61 |
| - Object value = new Object(); |
62 | 61 |
|
63 | 62 | // NOTE(norswap, 16 Apr 20): We could have used a WeakReference here, but the hope is that the extra
|
64 | 63 | // indirection will prevent the compiler to optimize this method away (assuming JIT compilation, and
|
65 | 64 | // the fact that such an optimizaton is permitted and possible, both of which are unlikely).
|
66 | 65 | WeakValueCache<Object, Object> cache = new WeakValueCache<>();
|
| 66 | + Object key = new Object(); |
| 67 | + |
| 68 | + // NOTE(norswap, 02 Feb 21): The split into two methods here is another way to try to outwit optimizations |
| 69 | + // by making sure the method that allocates the weak value is exited before we run the GC loop; |
| 70 | + initCache(cache, key); |
| 71 | + gcLoop(cache, key); |
| 72 | + return nil; |
| 73 | + } |
| 74 | + |
| 75 | + @SuppressFBWarnings("DLS") |
| 76 | + private void initCache(WeakValueCache<Object, Object> cache, Object key) { |
| 77 | + Object value = new Object(); |
67 | 78 | cache.put(key, value);
|
68 | 79 | value = null;
|
| 80 | + } |
69 | 81 |
|
| 82 | + private void gcLoop(WeakValueCache<Object, Object> cache, Object key) { |
| 83 | + final long duration = Duration.ofSeconds(60).toNanos(); |
| 84 | + final long start = System.nanoTime(); |
70 | 85 | do {
|
| 86 | + if (System.nanoTime() - start > duration) { |
| 87 | + throw new RaiseException( |
| 88 | + getContext(), |
| 89 | + getContext().getCoreExceptions().runtimeError( |
| 90 | + "gc_force exceeded its 60 seconds timeout", |
| 91 | + this)); |
| 92 | + } |
71 | 93 | System.gc();
|
72 | 94 | SafepointManager.poll(getLanguage(), this);
|
73 | 95 | } while (cache.get(key) != null);
|
74 |
| - |
75 |
| - return nil; |
76 | 96 | }
|
77 | 97 | }
|
78 | 98 |
|
|
0 commit comments