001/*
002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.hotspot.test;
024
025import java.util.*;
026
027import com.oracle.graal.debug.*;
028import com.oracle.graal.debug.Debug.*;
029import com.oracle.graal.debug.internal.*;
030import jdk.internal.jvmci.hotspot.*;
031import jdk.internal.jvmci.meta.*;
032
033import org.junit.*;
034
035import com.oracle.graal.compiler.test.*;
036import com.oracle.graal.hotspot.*;
037import com.oracle.graal.hotspot.nodes.*;
038import com.oracle.graal.hotspot.phases.*;
039import com.oracle.graal.hotspot.replacements.arraycopy.*;
040import com.oracle.graal.nodes.*;
041import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
042import com.oracle.graal.nodes.memory.*;
043import com.oracle.graal.nodes.spi.*;
044import com.oracle.graal.phases.*;
045import com.oracle.graal.phases.common.*;
046import com.oracle.graal.phases.common.inlining.*;
047import com.oracle.graal.phases.graph.*;
048import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
049import com.oracle.graal.phases.tiers.*;
050
051/**
052 * The following tests validate the write barrier verification phase. For every tested snippet, an
053 * array of write barrier indices and the total write barrier number are passed as parameters. The
054 * indices denote the barriers that will be manually removed. The write barrier verification phase
055 * runs after the write barrier removal and depending on the result an assertion might be generated.
056 * The tests anticipate the presence or not of an assertion generated by the verification phase.
057 */
058public class WriteBarrierVerificationTest extends GraalCompilerTest {
059
060    public static int barrierIndex;
061
062    private final HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
063
064    public static class Container {
065
066        public Container a;
067        public Container b;
068    }
069
070    private static native void safepoint();
071
072    public static void test1Snippet(Container main) {
073        Container temp1 = new Container();
074        Container temp2 = new Container();
075        barrierIndex = 0;
076        safepoint();
077        barrierIndex = 1;
078        main.a = temp1;
079        safepoint();
080        barrierIndex = 2;
081        main.b = temp2;
082        safepoint();
083    }
084
085    @Test(expected = AssertionError.class)
086    public void test1() {
087        test("test1Snippet", 2, new int[]{1});
088    }
089
090    @Test(expected = AssertionError.class)
091    public void test2() {
092        test("test1Snippet", 2, new int[]{2});
093    }
094
095    public static void test2Snippet(Container main) {
096        Container temp1 = new Container();
097        Container temp2 = new Container();
098        barrierIndex = 0;
099        safepoint();
100        barrierIndex = 1;
101        main.a = temp1;
102        barrierIndex = 2;
103        main.b = temp2;
104        safepoint();
105    }
106
107    @Test(expected = AssertionError.class)
108    public void test3() {
109        test("test2Snippet", 2, new int[]{1});
110    }
111
112    @Test
113    public void test4() {
114        test("test2Snippet", 2, new int[]{2});
115    }
116
117    public static void test3Snippet(Container main, boolean test) {
118        Container temp1 = new Container();
119        Container temp2 = new Container();
120        barrierIndex = 0;
121        safepoint();
122        for (int i = 0; i < 10; i++) {
123            if (test) {
124                barrierIndex = 1;
125                main.a = temp1;
126                barrierIndex = 2;
127                main.b = temp2;
128            } else {
129                barrierIndex = 3;
130                main.a = temp1;
131                barrierIndex = 4;
132                main.b = temp2;
133            }
134        }
135    }
136
137    @Test(expected = AssertionError.class)
138    public void test5() {
139        test("test3Snippet", 4, new int[]{1, 2});
140    }
141
142    @Test(expected = AssertionError.class)
143    public void test6() {
144        test("test3Snippet", 4, new int[]{3, 4});
145    }
146
147    @Test(expected = AssertionError.class)
148    public void test7() {
149        test("test3Snippet", 4, new int[]{1});
150    }
151
152    @Test
153    public void test8() {
154        test("test3Snippet", 4, new int[]{2});
155    }
156
157    @Test(expected = AssertionError.class)
158    public void test9() {
159        test("test3Snippet", 4, new int[]{3});
160    }
161
162    @Test
163    public void test10() {
164        test("test3Snippet", 4, new int[]{4});
165    }
166
167    public static void test4Snippet(Container main, boolean test) {
168        Container temp1 = new Container();
169        Container temp2 = new Container();
170        safepoint();
171        barrierIndex = 1;
172        main.a = temp1;
173        for (int i = 0; i < 10; i++) {
174            if (test) {
175                barrierIndex = 2;
176                main.a = temp1;
177                barrierIndex = 3;
178                main.b = temp2;
179            } else {
180                barrierIndex = 4;
181                main.a = temp2;
182                barrierIndex = 5;
183                main.b = temp1;
184            }
185        }
186    }
187
188    @Test(expected = AssertionError.class)
189    public void test11() {
190        test("test4Snippet", 5, new int[]{2, 3});
191    }
192
193    @Test(expected = AssertionError.class)
194    public void test12() {
195        test("test4Snippet", 5, new int[]{4, 5});
196    }
197
198    @Test(expected = AssertionError.class)
199    public void test13() {
200        test("test4Snippet", 5, new int[]{1});
201    }
202
203    public static void test5Snippet(Container main) {
204        Container temp1 = new Container();
205        Container temp2 = new Container();
206        safepoint();
207        barrierIndex = 1;
208        main.a = temp1;
209        if (main.a == main.b) {
210            barrierIndex = 2;
211            main.a = temp1;
212            barrierIndex = 3;
213            main.b = temp2;
214        } else {
215            barrierIndex = 4;
216            main.a = temp2;
217            barrierIndex = 5;
218            main.b = temp1;
219        }
220        safepoint();
221    }
222
223    @Test(expected = AssertionError.class)
224    public void test14() {
225        test("test5Snippet", 5, new int[]{1});
226    }
227
228    @Test
229    public void test15() {
230        test("test5Snippet", 5, new int[]{2});
231    }
232
233    @Test
234    public void test16() {
235        test("test5Snippet", 5, new int[]{4});
236    }
237
238    @Test
239    public void test17() {
240        test("test5Snippet", 5, new int[]{3});
241    }
242
243    @Test
244    public void test18() {
245        test("test5Snippet", 5, new int[]{5});
246    }
247
248    @Test
249    public void test19() {
250        test("test5Snippet", 5, new int[]{2, 3});
251    }
252
253    @Test
254    public void test20() {
255        test("test5Snippet", 5, new int[]{4, 5});
256    }
257
258    public static void test6Snippet(Container main, boolean test) {
259        Container temp1 = new Container();
260        Container temp2 = new Container();
261        safepoint();
262        barrierIndex = 1;
263        main.a = temp1;
264        if (test) {
265            barrierIndex = 2;
266            main.a = temp1;
267            barrierIndex = 3;
268            main.b = temp1.a.a;
269        } else {
270            barrierIndex = 4;
271            main.a = temp2;
272            barrierIndex = 5;
273            main.b = temp2.a.a;
274        }
275        safepoint();
276    }
277
278    @Test(expected = AssertionError.class)
279    public void test21() {
280        test("test6Snippet", 5, new int[]{1});
281    }
282
283    @Test(expected = AssertionError.class)
284    public void test22() {
285        test("test6Snippet", 5, new int[]{1, 2});
286    }
287
288    @Test(expected = AssertionError.class)
289    public void test23() {
290        test("test6Snippet", 5, new int[]{3});
291    }
292
293    @Test
294    public void test24() {
295        test("test6Snippet", 5, new int[]{4});
296    }
297
298    public static void test7Snippet(Container main, boolean test) {
299        Container temp1 = new Container();
300        Container temp2 = new Container();
301        safepoint();
302        barrierIndex = 1;
303        main.a = temp1;
304        if (test) {
305            barrierIndex = 2;
306            main.a = temp1;
307        }
308        barrierIndex = 3;
309        main.b = temp2;
310        safepoint();
311    }
312
313    @Test
314    public void test25() {
315        test("test7Snippet", 3, new int[]{2});
316    }
317
318    @Test
319    public void test26() {
320        test("test7Snippet", 3, new int[]{3});
321    }
322
323    @Test
324    public void test27() {
325        test("test7Snippet", 3, new int[]{2, 3});
326    }
327
328    @Test(expected = AssertionError.class)
329    public void test28() {
330        test("test7Snippet", 3, new int[]{1});
331    }
332
333    public static void test8Snippet(Container main, boolean test) {
334        Container temp1 = new Container();
335        Container temp2 = new Container();
336        safepoint();
337        if (test) {
338            barrierIndex = 1;
339            main.a = temp1;
340        }
341        barrierIndex = 2;
342        main.b = temp2;
343        safepoint();
344    }
345
346    @Test(expected = AssertionError.class)
347    public void test29() {
348        test("test8Snippet", 2, new int[]{1});
349    }
350
351    @Test(expected = AssertionError.class)
352    public void test30() {
353        test("test8Snippet", 2, new int[]{2});
354    }
355
356    @Test(expected = AssertionError.class)
357    public void test31() {
358        test("test8Snippet", 2, new int[]{1, 2});
359    }
360
361    public static void test9Snippet(Container main1, Container main2, boolean test) {
362        Container temp1 = new Container();
363        Container temp2 = new Container();
364        safepoint();
365        if (test) {
366            barrierIndex = 1;
367            main1.a = temp1;
368        } else {
369            barrierIndex = 2;
370            main2.a = temp1;
371        }
372        barrierIndex = 3;
373        main1.b = temp2;
374        barrierIndex = 4;
375        main2.b = temp2;
376        safepoint();
377    }
378
379    @Test(expected = AssertionError.class)
380    public void test32() {
381        test("test9Snippet", 4, new int[]{1});
382    }
383
384    @Test(expected = AssertionError.class)
385    public void test33() {
386        test("test9Snippet", 4, new int[]{2});
387    }
388
389    @Test(expected = AssertionError.class)
390    public void test34() {
391        test("test9Snippet", 4, new int[]{3});
392    }
393
394    @Test(expected = AssertionError.class)
395    public void test35() {
396        test("test9Snippet", 4, new int[]{4});
397    }
398
399    @Test(expected = AssertionError.class)
400    public void test36() {
401        test("test9Snippet", 4, new int[]{1, 2});
402    }
403
404    @Test(expected = AssertionError.class)
405    public void test37() {
406        test("test9Snippet", 4, new int[]{3, 4});
407    }
408
409    public static void test10Snippet(Container main1, Container main2, boolean test) {
410        Container temp1 = new Container();
411        Container temp2 = new Container();
412        safepoint();
413        if (test) {
414            barrierIndex = 1;
415            main1.a = temp1;
416            barrierIndex = 2;
417            main2.a = temp2;
418        } else {
419            barrierIndex = 3;
420            main2.a = temp1;
421        }
422        barrierIndex = 4;
423        main1.b = temp2;
424        barrierIndex = 5;
425        main2.b = temp2;
426        safepoint();
427    }
428
429    @Test(expected = AssertionError.class)
430    public void test38() {
431        test("test10Snippet", 5, new int[]{1});
432    }
433
434    @Test(expected = AssertionError.class)
435    public void test39() {
436        test("test10Snippet", 5, new int[]{2});
437    }
438
439    @Test(expected = AssertionError.class)
440    public void test40() {
441        test("test10Snippet", 5, new int[]{3});
442    }
443
444    @Test(expected = AssertionError.class)
445    public void test41() {
446        test("test10Snippet", 5, new int[]{4});
447    }
448
449    @Test
450    public void test42() {
451        test("test10Snippet", 5, new int[]{5});
452    }
453
454    @Test(expected = AssertionError.class)
455    public void test43() {
456        test("test10Snippet", 5, new int[]{1, 2});
457    }
458
459    @Test(expected = AssertionError.class)
460    public void test44() {
461        test("test10Snippet", 5, new int[]{1, 2, 3});
462    }
463
464    @Test(expected = AssertionError.class)
465    public void test45() {
466        test("test10Snippet", 5, new int[]{3, 4});
467    }
468
469    public static void test11Snippet(Container main1, Container main2, Container main3, boolean test) {
470        Container temp1 = new Container();
471        Container temp2 = new Container();
472        safepoint();
473        if (test) {
474            barrierIndex = 1;
475            main1.a = temp1;
476            barrierIndex = 2;
477            main3.a = temp1;
478            if (!test) {
479                barrierIndex = 3;
480                main2.a = temp2;
481            } else {
482                barrierIndex = 4;
483                main1.a = temp2;
484                barrierIndex = 5;
485                main3.a = temp2;
486            }
487        } else {
488            barrierIndex = 6;
489            main1.b = temp2;
490            for (int i = 0; i < 10; i++) {
491                barrierIndex = 7;
492                main3.a = temp1;
493            }
494            barrierIndex = 8;
495            main3.b = temp2;
496        }
497        barrierIndex = 9;
498        main1.b = temp2;
499        barrierIndex = 10;
500        main2.b = temp2;
501        barrierIndex = 11;
502        main3.b = temp2;
503        safepoint();
504    }
505
506    @Test(expected = AssertionError.class)
507    public void test46() {
508        test("test11Snippet", 11, new int[]{1});
509    }
510
511    @Test(expected = AssertionError.class)
512    public void test47() {
513        test("test11Snippet", 11, new int[]{2});
514    }
515
516    @Test(expected = AssertionError.class)
517    public void test48() {
518        test("test11Snippet", 11, new int[]{3});
519    }
520
521    @Test(expected = AssertionError.class)
522    public void test49() {
523        test("test11Snippet", 11, new int[]{6});
524    }
525
526    @Test(expected = AssertionError.class)
527    public void test50() {
528        test("test11Snippet", 11, new int[]{7});
529    }
530
531    @Test(expected = AssertionError.class)
532    public void test51() {
533        test("test11Snippet", 11, new int[]{8});
534    }
535
536    @Test(expected = AssertionError.class)
537    public void test52() {
538        test("test11Snippet", 11, new int[]{9});
539    }
540
541    @Test(expected = AssertionError.class)
542    public void test53() {
543        test("test11Snippet", 11, new int[]{10});
544    }
545
546    @Test
547    public void test54() {
548        test("test11Snippet", 11, new int[]{4});
549    }
550
551    @Test
552    public void test55() {
553        test("test11Snippet", 11, new int[]{5});
554    }
555
556    @Test
557    public void test56() {
558        test("test11Snippet", 11, new int[]{11});
559    }
560
561    public static void test12Snippet(Container main, Container main1, boolean test) {
562        Container temp1 = new Container();
563        Container temp2 = new Container();
564        barrierIndex = 0;
565        safepoint();
566        barrierIndex = 7;
567        main1.a = temp1;
568        for (int i = 0; i < 10; i++) {
569            if (test) {
570                barrierIndex = 1;
571                main.a = temp1;
572                barrierIndex = 2;
573                main.b = temp2;
574            } else {
575                barrierIndex = 3;
576                main.a = temp1;
577                barrierIndex = 4;
578                main.b = temp2;
579            }
580        }
581        barrierIndex = 5;
582        main.a = temp1;
583        barrierIndex = 6;
584        main.b = temp1;
585        barrierIndex = 8;
586        main1.b = temp1;
587        safepoint();
588    }
589
590    @Test(expected = AssertionError.class)
591    public void test57() {
592        test("test12Snippet", 8, new int[]{5});
593    }
594
595    @Test
596    public void test58() {
597        test("test12Snippet", 8, new int[]{6});
598    }
599
600    @Test(expected = AssertionError.class)
601    public void test59() {
602        test("test12Snippet", 8, new int[]{7});
603    }
604
605    @Test(expected = AssertionError.class)
606    public void test60() {
607        test("test12Snippet", 8, new int[]{8});
608    }
609
610    public static void test13Snippet(Object[] a, Object[] b) {
611        System.arraycopy(a, 0, b, 0, a.length);
612    }
613
614    @Test
615    public void test61() {
616        GraphPredicate checkForUnsafeArrayCopy = graph -> graph.getNodes().filter(UnsafeArrayCopyNode.class).count() > 0 ? 1 : 0;
617        testPredicate("test13Snippet", checkForUnsafeArrayCopy, new int[]{});
618    }
619
620    private interface GraphPredicate {
621        int apply(StructuredGraph graph);
622    }
623
624    private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) {
625        GraphPredicate noCheck = noArg -> expectedBarriers;
626        testPredicate(snippet, noCheck, removedBarrierIndices);
627    }
628
629    private void testPredicate(final String snippet, final GraphPredicate expectedBarriers, final int... removedBarrierIndices) {
630        try (Scope d = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet))) {
631            final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
632            HighTierContext highTierContext = getDefaultHighTierContext();
633            new InliningPhase(new CanonicalizerPhase()).apply(graph, highTierContext);
634
635            MidTierContext midTierContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo());
636
637            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
638            new GuardLoweringPhase().apply(graph, midTierContext);
639            new LoopSafepointInsertionPhase().apply(graph);
640            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, highTierContext);
641
642            new WriteBarrierAdditionPhase(config).apply(graph);
643
644            int barriers = 0;
645            // First, the total number of expected barriers is checked.
646            if (config.useG1GC) {
647                barriers = graph.getNodes().filter(G1PreWriteBarrier.class).count() + graph.getNodes().filter(G1PostWriteBarrier.class).count() +
648                                graph.getNodes().filter(G1ArrayRangePreWriteBarrier.class).count() + graph.getNodes().filter(G1ArrayRangePostWriteBarrier.class).count();
649                Assert.assertTrue(expectedBarriers.apply(graph) * 2 == barriers);
650            } else {
651                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count() + graph.getNodes().filter(SerialArrayRangeWriteBarrier.class).count();
652                Assert.assertTrue(expectedBarriers.apply(graph) == barriers);
653            }
654            // Iterate over all write nodes and remove barriers according to input indices.
655            NodeIteratorClosure<Boolean> closure = new NodeIteratorClosure<Boolean>() {
656
657                @Override
658                protected Boolean processNode(FixedNode node, Boolean currentState) {
659                    if (node instanceof WriteNode) {
660                        WriteNode write = (WriteNode) node;
661                        LocationIdentity obj = write.getLocationIdentity();
662                        if (obj.toString().equals("barrierIndex")) {
663                            /*
664                             * A "barrierIndex" variable was found and is checked against the input
665                             * barrier array.
666                             */
667                            if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) {
668                                return true;
669                            }
670                        }
671                    } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) {
672                        // Remove flagged write barriers.
673                        if (currentState) {
674                            graph.removeFixed(((FixedWithNextNode) node));
675                            return false;
676                        }
677                    }
678                    return currentState;
679                }
680
681                private boolean eliminateBarrier(int index, int[] map) {
682                    for (int i = 0; i < map.length; i++) {
683                        if (map[i] == index) {
684                            return true;
685                        }
686                    }
687                    return false;
688                }
689
690                @Override
691                protected Map<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
692                    return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
693                }
694
695                @Override
696                protected Boolean merge(AbstractMergeNode merge, List<Boolean> states) {
697                    return false;
698                }
699
700                @Override
701                protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
702                    return false;
703                }
704            };
705
706            DebugConfig debugConfig = DebugScope.getConfig();
707            DebugConfig fixedConfig = debugConfig == null ? null : Debug.fixedConfig(0, 0, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output());
708            try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
709                ReentrantNodeIterator.apply(closure, graph.start(), false);
710                new WriteBarrierVerificationPhase().apply(graph);
711            } catch (AssertionError error) {
712                /*
713                 * Catch assertion, test for expected one and re-throw in order to validate unit
714                 * test.
715                 */
716                Assert.assertTrue(error.getMessage().contains("Write barrier must be present"));
717                throw error;
718            }
719        } catch (Throwable e) {
720            throw Debug.handle(e);
721        }
722    }
723}