001/*
002 * Copyright (c) 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.truffle.test;
024
025import org.junit.*;
026
027import com.oracle.graal.truffle.test.nodes.*;
028import com.oracle.truffle.api.*;
029import com.oracle.truffle.api.frame.*;
030import com.oracle.truffle.api.instrument.*;
031import com.oracle.truffle.api.instrument.impl.*;
032import com.oracle.truffle.api.nodes.*;
033
034/**
035 * Tests for a single simple PE test with various combinations of instrumentation attached. None of
036 * the instrumentation ultimate does anything, so should compile away.
037 */
038public class InstrumentationPartialEvaluationTest extends PartialEvaluationTest {
039
040    public static Object constant42() {
041        return 42;
042    }
043
044    @Test
045    public void constantValueUninstrumented() {
046        FrameDescriptor fd = new FrameDescriptor();
047        AbstractTestNode result = new ConstantTestNode(42);
048        RootTestNode root = new RootTestNode(fd, "constantValue", result);
049        root.adoptChildren();
050        assertPartialEvalEquals("constant42", root);
051    }
052
053    @Test
054    public void constantValueProbedNoInstruments() {
055        FrameDescriptor fd = new FrameDescriptor();
056        AbstractTestNode result = new ConstantTestNode(42);
057        RootTestNode root = new RootTestNode(fd, "constantValue", result);
058        root.adoptChildren();
059        result.probe();
060        assertPartialEvalEquals("constant42", root);
061    }
062
063    @Test
064    public void constantValueProbedNullInstrument1() {
065        FrameDescriptor fd = new FrameDescriptor();
066        AbstractTestNode result = new ConstantTestNode(42);
067        RootTestNode root = new RootTestNode(fd, "constantValue", result);
068        root.adoptChildren();
069        Probe probe = result.probe();
070        Instrument instrument = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument");
071        probe.attach(instrument);
072        assertPartialEvalEquals("constant42", root);
073    }
074
075    @Test
076    public void constantValueProbedNullInstrument2() {
077        FrameDescriptor fd = new FrameDescriptor();
078        AbstractTestNode result = new ConstantTestNode(42);
079        RootTestNode root = new RootTestNode(fd, "constantValue", result);
080        root.adoptChildren();
081        Probe probe = result.probe();
082        Instrument instrument = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument");
083        probe.attach(instrument);
084        assertPartialEvalEquals("constant42", root);
085    }
086
087    @Test
088    public void constantValueProbedNullInstrumentDisposed1() {
089        FrameDescriptor fd = new FrameDescriptor();
090        AbstractTestNode result = new ConstantTestNode(42);
091        RootTestNode root = new RootTestNode(fd, "constantValue", result);
092        root.adoptChildren();
093        Probe probe = result.probe();
094        Instrument instrument = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument");
095        probe.attach(instrument);
096        instrument.dispose();
097        assertPartialEvalEquals("constant42", root);
098    }
099
100    @Test
101    public void constantValueProbedNullInstrumentDisposed2() {
102        FrameDescriptor fd = new FrameDescriptor();
103        AbstractTestNode result = new ConstantTestNode(42);
104        RootTestNode root = new RootTestNode(fd, "constantValue", result);
105        root.adoptChildren();
106        Probe probe = result.probe();
107        Instrument instrument = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument");
108        probe.attach(instrument);
109        instrument.dispose();
110        assertPartialEvalEquals("constant42", root);
111    }
112
113    @Test
114    public void constantValueProbedTwoNullInstruments1() {
115        FrameDescriptor fd = new FrameDescriptor();
116        AbstractTestNode result = new ConstantTestNode(42);
117        RootTestNode root = new RootTestNode(fd, "constantValue", result);
118        root.adoptChildren();
119        Probe probe = result.probe();
120        Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 1");
121        probe.attach(instrument1);
122        Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 2");
123        probe.attach(instrument2);
124        assertPartialEvalEquals("constant42", root);
125    }
126
127    @Test
128    public void constantValueProbedTwoNullInstruments2() {
129        FrameDescriptor fd = new FrameDescriptor();
130        AbstractTestNode result = new ConstantTestNode(42);
131        RootTestNode root = new RootTestNode(fd, "constantValue", result);
132        root.adoptChildren();
133        Probe probe = result.probe();
134        Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 1");
135        probe.attach(instrument1);
136        Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 2");
137        probe.attach(instrument2);
138        assertPartialEvalEquals("constant42", root);
139    }
140
141    @Test
142    public void constantValueProbedThreeNullInstruments1() {
143        FrameDescriptor fd = new FrameDescriptor();
144        AbstractTestNode result = new ConstantTestNode(42);
145        RootTestNode root = new RootTestNode(fd, "constantValue", result);
146        root.adoptChildren();
147        Probe probe = result.probe();
148        Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 1");
149        probe.attach(instrument1);
150        Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 2");
151        probe.attach(instrument2);
152        Instrument instrument3 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 3");
153        probe.attach(instrument3);
154        assertPartialEvalEquals("constant42", root);
155    }
156
157    @Test
158    public void constantValueProbedThreeNullInstruments2() {
159        FrameDescriptor fd = new FrameDescriptor();
160        AbstractTestNode result = new ConstantTestNode(42);
161        RootTestNode root = new RootTestNode(fd, "constantValue", result);
162        root.adoptChildren();
163        Probe probe = result.probe();
164        Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 1");
165        probe.attach(instrument1);
166        Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 2");
167        probe.attach(instrument2);
168        Instrument instrument3 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 3");
169        probe.attach(instrument3);
170        assertPartialEvalEquals("constant42", root);
171    }
172
173    @Test
174    public void constantValueProbedThreeNullInstrumentsOneDisposed1() {
175        FrameDescriptor fd = new FrameDescriptor();
176        AbstractTestNode result = new ConstantTestNode(42);
177        RootTestNode root = new RootTestNode(fd, "constantValue", result);
178        root.adoptChildren();
179        Probe probe = result.probe();
180        Instrument instrument1 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 1");
181        probe.attach(instrument1);
182        Instrument instrument2 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 2");
183        probe.attach(instrument2);
184        Instrument instrument3 = Instrument.create(new DefaultSimpleInstrumentListener(), "Null test Instrument 3");
185        probe.attach(instrument3);
186        instrument2.dispose();
187        assertPartialEvalEquals("constant42", root);
188    }
189
190    @Test
191    public void constantValueProbedThreeNullInstrumentsOneDisposed2() {
192        FrameDescriptor fd = new FrameDescriptor();
193        AbstractTestNode result = new ConstantTestNode(42);
194        RootTestNode root = new RootTestNode(fd, "constantValue", result);
195        root.adoptChildren();
196        Probe probe = result.probe();
197        Instrument instrument1 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 1");
198        probe.attach(instrument1);
199        Instrument instrument2 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 2");
200        probe.attach(instrument2);
201        Instrument instrument3 = Instrument.create(new DefaultStandardInstrumentListener(), "Null test Instrument 3");
202        probe.attach(instrument3);
203        instrument2.dispose();
204        assertPartialEvalEquals("constant42", root);
205    }
206
207    @Test
208    public void constantValueInertAdvancedInstrumentRootFactory() {
209        FrameDescriptor fd = new FrameDescriptor();
210        AbstractTestNode result = new ConstantTestNode(42);
211        RootTestNode root = new RootTestNode(fd, "constantValue", result);
212        root.adoptChildren();
213        Probe testProbe = result.probe();
214        // A factory that could insert a AdvancedInstrumentRoot into the AST, but which never does.
215        Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
216
217            public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
218                return null;
219            }
220        }, null, "test AdvancedInstrument");
221        testProbe.attach(instrument);
222
223        // It all gets compiled away
224        assertPartialEvalEquals("constant42", root);
225    }
226
227    @Test
228    public void constantValueInertAdvancedInstrumentRoot() {
229        FrameDescriptor fd = new FrameDescriptor();
230        AbstractTestNode resultTestNode = new ConstantTestNode(42);
231        RootTestNode rootTestNode = new RootTestNode(fd, "constantValue", resultTestNode);
232        rootTestNode.adoptChildren();
233        Probe testProbe = resultTestNode.probe();
234        // Factory inserts a AdvancedInstrumentRoot with empty methods into instrumentation .
235        Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
236
237            @Override
238            public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
239                return new AdvancedInstrumentRoot() {
240
241                    public String instrumentationInfo() {
242                        return null;
243                    }
244
245                    @Override
246                    public Object executeRoot(Node n, VirtualFrame frame) {
247                        return null;
248                    }
249                };
250            }
251        }, null, "test AdvancedInstrument");
252        testProbe.attach(instrument);
253
254        // It all gets compiled away.
255        assertPartialEvalEquals("constant42", rootTestNode);
256    }
257
258    @Test
259    public void instrumentDeopt() {
260        final FrameDescriptor fd = new FrameDescriptor();
261        final AbstractTestNode result = new ConstantTestNode(42);
262        final RootTestNode root = new RootTestNode(fd, "constantValue", result);
263        final Probe[] probe = new Probe[1];
264        final int[] count = {1};
265        count[0] = 0;
266        // Register a "prober" that will get applied when CallTarget gets created.
267        final ASTProber prober = new ASTProber() {
268
269            @Override
270            public void probeAST(Node node) {
271                node.accept(new NodeVisitor() {
272
273                    @Override
274                    public boolean visit(Node visitedNode) {
275                        if (visitedNode instanceof ConstantTestNode) {
276                            probe[0] = visitedNode.probe();
277                        }
278                        return true;
279                    }
280
281                });
282            }
283        };
284        Probe.registerASTProber(prober);
285        try {
286            final RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(root);
287
288            // The CallTarget has one Probe, attached to the ConstantTestNode, ready to run
289            Assert.assertEquals(42, callTarget.call()); // Correct result
290            Assert.assertEquals(0, count[0]);           // Didn't count anything
291
292            // Add a counting instrument; this changes the "Probe state" and should cause a deopt
293            final Instrument countingInstrument = Instrument.create(new DefaultSimpleInstrumentListener() {
294
295                @Override
296                public void enter(Probe p) {
297                    count[0] = count[0] + 1;
298                }
299            }, null);
300            probe[0].attach(countingInstrument);
301
302            Assert.assertEquals(42, callTarget.call()); // Correct result
303            Assert.assertEquals(1, count[0]);           // Counted the first call
304
305            // Remove the counting instrument; this changes the "Probe state" and should cause a
306            // deopt
307            countingInstrument.dispose();
308
309            Assert.assertEquals(42, callTarget.call()); // Correct result
310            Assert.assertEquals(1, count[0]);           // Didn't count this time
311        } finally {
312            Probe.unregisterASTProber(prober);
313        }
314
315    }
316
317    /**
318     * Experimental feature; not yet validated.
319     */
320    @Test
321    public void specialOptInstrument() {
322        final FrameDescriptor fd = new FrameDescriptor();
323        final AbstractTestNode result = new ConstantTestNode(42);
324        final RootTestNode root = new RootTestNode(fd, "constantValue", result);
325        final Probe[] probe = new Probe[1];
326        final int[] count = {1};
327        count[0] = 0;
328        // Register a "prober" that will get applied when CallTarget gets created.
329        final ASTProber prober = new ASTProber() {
330
331            @Override
332            public void probeAST(Node node) {
333                node.accept(new NodeVisitor() {
334
335                    @Override
336                    public boolean visit(Node visitedNode) {
337                        if (visitedNode instanceof ConstantTestNode) {
338                            probe[0] = visitedNode.probe();
339                        }
340                        return true;
341                    }
342                });
343            }
344        };
345        Probe.registerASTProber(prober);
346        try {
347            final RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(root);
348
349            // The CallTarget has one Probe, attached to the ConstantTestNode, ready to run
350            Assert.assertEquals(42, callTarget.call()); // Correct result
351
352            final boolean[] isCurrentlyCompiled = {false};
353            final Instrument optInstrument = Instrument.create(new Instrument.TruffleOptListener() {
354
355                @Override
356                public void notifyIsCompiled(boolean isCompiled) {
357                    isCurrentlyCompiled[0] = isCompiled;
358                }
359            });
360            probe[0].attach(optInstrument);
361
362            Assert.assertEquals(42, callTarget.call()); // Correct result
363            Assert.assertFalse(isCurrentlyCompiled[0]);
364
365            // TODO (mlvdv) compile, call again, and assert that isCurrentlyCompiled == true
366
367        } finally {
368            Probe.unregisterASTProber(prober);
369        }
370
371    }
372}