aboutsummaryrefslogtreecommitdiff
path: root/compiler/test/dotty/tools/ContextEscapeDetector.java
blob: e19fc5a64432b091b285cc95bde72c02306d4ca7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package dotty.tools;

import org.junit.runner.Result;
import org.junit.runner.notification.RunListener;
import org.junit.Assert;
import java.lang.ref.WeakReference;

public class ContextEscapeDetector extends RunListener {

    //context can be captured by objects, eg NoDenotation
    public static final int CONTEXTS_ALLOWED = 1;

    @Override
    public void testRunFinished(Result result) throws Exception {
        if (contextsAlive() > CONTEXTS_ALLOWED) {
            forceGCHeuristic0();
            if (contextsAlive() > CONTEXTS_ALLOWED) {
                forceGCHeuristic1();
                if (contextsAlive() > CONTEXTS_ALLOWED) {
                    forceGCHeuristic2();
                    forceGCHeuristic1();
                    int contextAlive = contextsAlive();
                    if (contextAlive > CONTEXTS_ALLOWED) {
                        StringBuilder names = new StringBuilder();
                        for (ContextEscapeDetection.TestContext ref : ContextEscapeDetection.contexts) {
                            if (ref.context.get() != null) names.append(ref.testName).append(' ');
                        }
                        Assert.fail("Multiple contexts survived test suite: " + names.toString());
                    }
                }
            }
        }
        super.testRunFinished(result);
    }

    private static synchronized int contextsAlive() {
        int count = 0;
        for (ContextEscapeDetection.TestContext ref : ContextEscapeDetection.contexts) {
            if (ref.context.get() != null) count++;
        }
        return count;
    }

    @SuppressWarnings("unused")
    private static volatile Object o = null;

    private static synchronized void forceGCHeuristic0() {
        System.gc();
        Runtime.getRuntime().gc();
        System.gc();
        Runtime.getRuntime().gc();
        System.gc();
        Runtime.getRuntime().gc();
        System.gc();
        Runtime.getRuntime().gc();
        System.gc();
    }

    private static synchronized void forceGCHeuristic1() {
        Object obj = new Object();
        WeakReference<Object> ref = new WeakReference<>(obj);
        obj = null;
        while (ref.get() != null) {
            System.gc();
        }
    }

    private static synchronized void forceGCHeuristic2() {
        try {
            Object[] arr = new Object[1024]; // upto 8 GB
            WeakReference<Object> ref = new WeakReference<>(arr);
            o = arr; // make sure array isn't optimized away

            Runtime runtime = Runtime.getRuntime();
            // allocate memory until no more that 64MB is left
            for (int i = 0; i < 1024 &&
                    runtime.totalMemory() != runtime.maxMemory() ||
                    runtime.freeMemory() < 1024 * 1024 * 64; i++) {
                int[] data = new int[1024 * 1024]; // 8MB
                for (int j = 0; j < 1024 * 1024; j++) {
                    data[j] = j; // force actual pages allocation
                }
                arr[i] = data;
            }
            o = null;
            arr = new Object[128];
            o = arr;
            // allocate 1 more GB
            for (int i = 0; i < 128; i++) {
                int[] data = new int[1024 * 1024]; // 8MB
                for (int j = 0; j < 1024 * 1024; j++) {
                    data[j] = j; // force actual pages allocation
                }
                arr[i] = data;
            }
            o = null;
            arr = null;

            forceGCHeuristic0();
            while (ref.get() != null) {
                System.gc();
            }
        } catch (OutOfMemoryError e) {
            o = null;
            // just swallow
        }
    }
}