Skip to content

Commit 8041ea5

Browse files
committed
[GR-33322] Support for Execute tracing in Truffle DSL
PullRequest: graal/9650
2 parents 434c20d + d81101a commit 8041ea5

File tree

12 files changed

+655
-20
lines changed

12 files changed

+655
-20
lines changed

truffle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ This changelog summarizes major changes between Truffle versions relevant to lan
2525
* Added `--engine.TraceDeoptimizeFrame` to trace frame deoptimizations due to `FrameInstance#getFrame(READ_WRITE|MATERIALIZE)`.
2626
* Added loop condition profiling to `LoopNode`, so the `RepeatingNode` no longer needs to profile or inject the loop count. Language implementations should remove loop condition profiles from their repeating nodes since they are redundant now.
2727
* Added `ThreadLocalAction` constructor that allows to configure recurring thread local actions to be performed repeatedly. This allows to build debug tooling that need to gather information in every safepoint poll of a thread.
28+
* Added `ExecuteTracingSupport` interface that allows tracing the calls to `execute` methods of a `Node`.
2829

2930
## Version 21.2.0
3031
* Added `TypeDescriptor.subtract(TypeDescriptor)` creating a new `TypeDescriptor` by removing the given type from a union or intersection type.

truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AOTSupportTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ public static final class ErrorMergedLibrary {
902902
@SuppressWarnings("static-method")
903903
@ExportMessage
904904
int m0(Object arg0,
905-
@ExpectError("Merged librares are not supported in combination with AOT preparation. Resolve this problem by either: %n" +
905+
@ExpectError("Merged libraries are not supported in combination with AOT preparation. Resolve this problem by either: %n" +
906906
" - Setting @ExportLibrary(..., useForAOT=false) to disable AOT preparation for this export. %n" +
907907
" - Using a dispatched library without receiver expression. %n" +
908908
" - Adding the @GenerateAOT.Exclude annotation to the specialization or exported method.")//
@@ -916,7 +916,7 @@ static class M1 {
916916
@SuppressWarnings("static-method")
917917
@Specialization
918918
static int doDefault(ErrorMergedLibrary receiver,
919-
@ExpectError("Merged librares are not supported in combination with AOT preparation. Resolve this problem by either: %n" +
919+
@ExpectError("Merged libraries are not supported in combination with AOT preparation. Resolve this problem by either: %n" +
920920
" - Setting @ExportLibrary(..., useForAOT=false) to disable AOT preparation for this export. %n" +
921921
" - Using a dispatched library without receiver expression. %n" +
922922
" - Adding the @GenerateAOT.Exclude annotation to the specialization or exported method.")//
Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.api.dsl.test;
42+
43+
import static org.junit.Assert.assertArrayEquals;
44+
import static org.junit.Assert.assertEquals;
45+
import static org.junit.Assert.assertNull;
46+
import static org.junit.Assert.assertSame;
47+
import static org.junit.Assert.fail;
48+
49+
import com.oracle.truffle.api.library.ExportLibrary;
50+
import com.oracle.truffle.api.library.ExportMessage;
51+
import com.oracle.truffle.api.library.GenerateLibrary;
52+
import com.oracle.truffle.api.library.Library;
53+
import org.junit.Before;
54+
import org.junit.Test;
55+
56+
import com.oracle.truffle.api.dsl.ExecuteTracingSupport;
57+
import com.oracle.truffle.api.dsl.GenerateUncached;
58+
import com.oracle.truffle.api.dsl.NodeChild;
59+
import com.oracle.truffle.api.dsl.Specialization;
60+
import com.oracle.truffle.api.dsl.test.ExecuteTracingSupportTestFactory.ConstNodeGen;
61+
import com.oracle.truffle.api.dsl.test.ExecuteTracingSupportTestFactory.DivNodeGen;
62+
import com.oracle.truffle.api.dsl.test.ExecuteTracingSupportTestFactory.ObjectArrayArgNodeGen;
63+
import com.oracle.truffle.api.dsl.test.ExecuteTracingSupportTestFactory.OverloadedExecuteNodeGen;
64+
import com.oracle.truffle.api.dsl.test.ExecuteTracingSupportTestFactory.TraceDisabledNodeGen;
65+
import com.oracle.truffle.api.dsl.test.ExecuteTracingSupportTestFactory.VoidExecuteWithNonVoidSpecializationNodeGen;
66+
import com.oracle.truffle.api.dsl.test.ExecuteTracingSupportTestFactory.VoidNoArgsNodeGen;
67+
import com.oracle.truffle.api.frame.VirtualFrame;
68+
import com.oracle.truffle.api.nodes.Node;
69+
70+
public class ExecuteTracingSupportTest {
71+
72+
private static int traceOnEnterCalled;
73+
private static int traceOnExceptionCalled;
74+
private static int traceOnReturnCalled;
75+
private static Object[] capturedArgs;
76+
private static Throwable capturedThrowable;
77+
private static Object capturedReturnValue;
78+
79+
@Before
80+
@SuppressWarnings("static-method")
81+
public final void setup() {
82+
traceOnEnterCalled = 0;
83+
traceOnExceptionCalled = 0;
84+
traceOnReturnCalled = 0;
85+
}
86+
87+
abstract static class TracingBaseNode extends Node implements ExecuteTracingSupport {
88+
@Override
89+
public boolean isTracingEnabled() {
90+
return true;
91+
}
92+
93+
@Override
94+
public void traceOnEnter(Object[] arguments) {
95+
traceOnEnterCalled++;
96+
capturedArgs = arguments;
97+
}
98+
99+
@Override
100+
public void traceOnReturn(Object returnValue) {
101+
traceOnReturnCalled++;
102+
capturedReturnValue = returnValue;
103+
}
104+
105+
@Override
106+
public void traceOnException(Throwable t) {
107+
traceOnExceptionCalled++;
108+
capturedThrowable = t;
109+
}
110+
}
111+
112+
abstract static class BaseNode extends TracingBaseNode {
113+
abstract Object execute(VirtualFrame frame);
114+
}
115+
116+
@NodeChild("left")
117+
@NodeChild("right")
118+
abstract static class DivNode extends BaseNode {
119+
@Specialization
120+
int doIt(int left, int right) {
121+
return left / right;
122+
}
123+
}
124+
125+
abstract static class ConstNode extends BaseNode {
126+
127+
private final int value;
128+
129+
ConstNode(int value) {
130+
this.value = value;
131+
}
132+
133+
@Specialization
134+
int doIt(@SuppressWarnings("unused") VirtualFrame frame) {
135+
return value;
136+
}
137+
}
138+
139+
@GenerateUncached
140+
abstract static class OverloadedExecuteNode extends TracingBaseNode {
141+
142+
abstract Object execute(int x, Object y);
143+
144+
abstract Object executeX(long a, Object b);
145+
146+
@Specialization
147+
int doIt(int a0, int a1) {
148+
return a0 / a1;
149+
}
150+
151+
@Specialization
152+
String doIt(int b0, String b1) {
153+
return b0 + b1;
154+
}
155+
156+
@Specialization
157+
double doIt(long c0, double c1) {
158+
return c0 + c1;
159+
}
160+
}
161+
162+
abstract static class TraceDisabledNode extends TracingBaseNode {
163+
abstract Object execute(int x);
164+
165+
@Override
166+
public boolean isTracingEnabled() {
167+
return false;
168+
}
169+
170+
@Specialization
171+
Object doIt(int x) {
172+
return 24 / x;
173+
}
174+
}
175+
176+
abstract static class VoidNoArgsNode extends TracingBaseNode {
177+
abstract void execute();
178+
179+
@Specialization
180+
void doIt() {
181+
}
182+
}
183+
184+
abstract static class VoidExecuteWithNonVoidSpecializationNode extends TracingBaseNode {
185+
abstract void execute(int a);
186+
187+
abstract long execute(long a);
188+
189+
@Specialization
190+
long doInt(int a) {
191+
return a;
192+
}
193+
194+
@Specialization
195+
long doLong(long a) {
196+
return a;
197+
}
198+
}
199+
200+
abstract static class ObjectArrayArgNode extends TracingBaseNode {
201+
abstract Object execute(Object[] arg);
202+
203+
@Specialization
204+
Object doInt(Object[] arg) {
205+
return arg;
206+
}
207+
}
208+
209+
@Test
210+
public void testChildren() {
211+
assertEquals(14, DivNodeGen.create(ConstNodeGen.create(42), ConstNodeGen.create(3)).execute(null));
212+
assertEquals(3, traceOnEnterCalled);
213+
assertArrayEquals(new Object[]{42, 3}, capturedArgs);
214+
assertEquals(3, traceOnReturnCalled);
215+
assertEquals(14, capturedReturnValue);
216+
}
217+
218+
@Test
219+
public void testOverloaded1() {
220+
assertEquals(2, OverloadedExecuteNodeGen.create().execute(14, 7));
221+
assertEquals(1, traceOnEnterCalled);
222+
assertArrayEquals(new Object[]{14, 7}, capturedArgs);
223+
assertEquals(1, traceOnReturnCalled);
224+
assertEquals(2, capturedReturnValue);
225+
}
226+
227+
@Test
228+
public void testOverloaded2() {
229+
assertEquals("14abc", OverloadedExecuteNodeGen.create().execute(14, "abc"));
230+
assertEquals(1, traceOnEnterCalled);
231+
assertArrayEquals(new Object[]{14, "abc"}, capturedArgs);
232+
assertEquals(1, traceOnReturnCalled);
233+
assertEquals("14abc", capturedReturnValue);
234+
}
235+
236+
@Test
237+
public void testOverloaded3() {
238+
assertEquals(17.14, OverloadedExecuteNodeGen.create().executeX(14, 3.14));
239+
assertEquals(1, traceOnEnterCalled);
240+
assertArrayEquals(new Object[]{14L, 3.14}, capturedArgs);
241+
assertEquals(1, traceOnReturnCalled);
242+
assertEquals(17.14, capturedReturnValue);
243+
}
244+
245+
@Test
246+
public void testUncached() {
247+
assertEquals(7, OverloadedExecuteNodeGen.getUncached().execute(14, 2));
248+
assertEquals(1, traceOnEnterCalled);
249+
assertArrayEquals(new Object[]{14, 2}, capturedArgs);
250+
assertEquals(1, traceOnReturnCalled);
251+
assertEquals(7, capturedReturnValue);
252+
}
253+
254+
@Test
255+
public void testDisabled() {
256+
assertEquals(6, TraceDisabledNodeGen.create().execute(4));
257+
assertEquals(0, traceOnEnterCalled);
258+
assertEquals(0, traceOnReturnCalled);
259+
}
260+
261+
@Test
262+
public void testVoidNoArgs() {
263+
VoidNoArgsNodeGen.create().execute();
264+
assertEquals(1, traceOnEnterCalled);
265+
assertArrayEquals(new Object[]{}, capturedArgs);
266+
assertEquals(1, traceOnReturnCalled);
267+
assertNull(capturedReturnValue);
268+
}
269+
270+
@Test
271+
public void testVoidExecuteWithNonVoidSpecialization() {
272+
// A void execute() overload is being invoked here, so traceOnReturn should be called with
273+
// null even though a @Specialization actually returns a value.
274+
VoidExecuteWithNonVoidSpecializationNodeGen.create().execute(14);
275+
assertEquals(1, traceOnEnterCalled);
276+
assertArrayEquals(new Object[]{14}, capturedArgs);
277+
assertEquals(1, traceOnReturnCalled);
278+
assertNull(capturedReturnValue);
279+
}
280+
281+
@Test
282+
public void testOnExceptionChildren() {
283+
try {
284+
DivNodeGen.create(ConstNodeGen.create(42), ConstNodeGen.create(0)).execute(null);
285+
fail();
286+
} catch (ArithmeticException e) {
287+
assertEquals(1, traceOnExceptionCalled);
288+
assertSame(e, capturedThrowable);
289+
}
290+
}
291+
292+
@Test
293+
public void testOnExceptionOverloaded() {
294+
try {
295+
OverloadedExecuteNodeGen.create().execute(14, 0);
296+
fail();
297+
} catch (ArithmeticException e) {
298+
assertEquals(1, traceOnExceptionCalled);
299+
assertSame(e, capturedThrowable);
300+
}
301+
}
302+
303+
@Test
304+
public void testOnExceptionUncached() {
305+
try {
306+
OverloadedExecuteNodeGen.getUncached().execute(14, 0);
307+
fail();
308+
} catch (ArithmeticException e) {
309+
assertEquals(1, traceOnExceptionCalled);
310+
assertSame(e, capturedThrowable);
311+
}
312+
}
313+
314+
@Test
315+
public void testOnExceptionDisabled() {
316+
try {
317+
TraceDisabledNodeGen.create().execute(0);
318+
fail();
319+
} catch (ArithmeticException e) {
320+
assertEquals(0, traceOnExceptionCalled);
321+
}
322+
}
323+
324+
@Test
325+
public void testObjectArrayArg() {
326+
Object[] arg = {42, "abc"};
327+
assertSame(arg, ObjectArrayArgNodeGen.create().execute(arg));
328+
assertEquals(1, traceOnEnterCalled);
329+
assertArrayEquals(new Object[]{arg}, capturedArgs);
330+
assertEquals(1, traceOnReturnCalled);
331+
assertSame(arg, capturedReturnValue);
332+
}
333+
334+
@GenerateLibrary
335+
public abstract static class ALibrary extends Library {
336+
public abstract Object aMessage(Object receiver, Object arg);
337+
}
338+
339+
@ExportLibrary(ALibrary.class)
340+
public static final class ALibraryImpl {
341+
@ExportMessage
342+
@ExpectError("@ExportMessage annotated nodes do not support execute tracing. Remove the ExecuteTracingSupport interface to resolve this.")
343+
public static class AMessage implements ExecuteTracingSupport {
344+
@Specialization
345+
static int doIt(@SuppressWarnings("unused") ALibraryImpl receiver, int arg) {
346+
return arg;
347+
}
348+
349+
@Override
350+
public boolean isTracingEnabled() {
351+
return true;
352+
}
353+
}
354+
}
355+
}

0 commit comments

Comments
 (0)