Skip to content

Commit db3cf9f

Browse files
committed
Add merge explode key marking
1 parent abdf91f commit db3cf9f

File tree

8 files changed

+545
-122
lines changed

8 files changed

+545
-122
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package jdk.graal.compiler.truffle.test;
26+
27+
import org.junit.Test;
28+
29+
import com.oracle.truffle.api.CompilerAsserts;
30+
import com.oracle.truffle.api.CompilerDirectives;
31+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
32+
import com.oracle.truffle.api.frame.FrameDescriptor;
33+
import com.oracle.truffle.api.frame.FrameSlotKind;
34+
import com.oracle.truffle.api.frame.VirtualFrame;
35+
import com.oracle.truffle.api.nodes.ExplodeLoop;
36+
import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind;
37+
import com.oracle.truffle.api.nodes.RootNode;
38+
39+
import jdk.vm.ci.code.BailoutException;
40+
41+
/**
42+
* Tests the `CompilerDirectives.mergeExplodeKey` system for explicit merge explode keys.
43+
*/
44+
@SuppressWarnings("deprecation")
45+
public class MergeExplodeKeyTest extends PartialEvaluationTest {
46+
47+
public static class Bytecode {
48+
public static final byte CONST = 0;
49+
public static final byte ARGUMENT = 1;
50+
public static final byte ADD = 2;
51+
public static final byte SUB = 3;
52+
public static final byte DUP = 4;
53+
public static final byte POP = 5;
54+
public static final byte JMP = 6;
55+
public static final byte IFZERO = 7;
56+
public static final byte RETURN = 8;
57+
}
58+
59+
public static class Program extends RootNode {
60+
protected final String name;
61+
@CompilationFinal(dimensions = 1) protected final byte[] bytecodes;
62+
protected final int stackOffset;
63+
protected final boolean markTopAsKey;
64+
65+
static Program create(String name, byte[] bytecodes, int maxStack, boolean markTopAsKey) {
66+
var builder = FrameDescriptor.newBuilder();
67+
int stackOffset = builder.addSlots(maxStack, FrameSlotKind.Int);
68+
return new Program(name, bytecodes, builder.build(), stackOffset, markTopAsKey);
69+
}
70+
71+
Program(String name, byte[] bytecodes, FrameDescriptor descriptor, int stackOffset, boolean markTopAsKey) {
72+
super(null, descriptor);
73+
this.name = name;
74+
this.bytecodes = bytecodes;
75+
this.stackOffset = stackOffset;
76+
this.markTopAsKey = markTopAsKey;
77+
}
78+
79+
protected void setInt(VirtualFrame frame, int stackIndex, int value) {
80+
frame.setInt(stackOffset + stackIndex, value);
81+
}
82+
83+
protected int getInt(VirtualFrame frame, int stackIndex) {
84+
return frame.getInt(stackOffset + stackIndex);
85+
}
86+
87+
@Override
88+
public String toString() {
89+
return name;
90+
}
91+
92+
@Override
93+
@ExplodeLoop(kind = LoopExplosionKind.MERGE_EXPLODE)
94+
public Object execute(VirtualFrame frame) {
95+
int top = -1;
96+
int bci = 0;
97+
bci = CompilerDirectives.mergeExplodeKey(bci);
98+
if (markTopAsKey) {
99+
/* Testing error on multiple key variables. */
100+
top = CompilerDirectives.mergeExplodeKey(top);
101+
}
102+
while (true) {
103+
CompilerAsserts.partialEvaluationConstant(bci);
104+
switch (bytecodes[bci]) {
105+
case Bytecode.CONST: {
106+
byte value = bytecodes[bci + 1];
107+
top++;
108+
setInt(frame, top, value);
109+
bci = bci + 2;
110+
continue;
111+
}
112+
case Bytecode.ARGUMENT: {
113+
int value = (int) frame.getArguments()[bytecodes[bci + 1]];
114+
top++;
115+
setInt(frame, top, value);
116+
bci = bci + 2;
117+
continue;
118+
}
119+
120+
case Bytecode.ADD: {
121+
int left = getInt(frame, top);
122+
int right = getInt(frame, top - 1);
123+
top--;
124+
setInt(frame, top, left + right);
125+
bci = bci + 1;
126+
continue;
127+
}
128+
case Bytecode.SUB: {
129+
int left = getInt(frame, top);
130+
int right = getInt(frame, top - 1);
131+
top--;
132+
setInt(frame, top, left - right);
133+
bci = bci + 1;
134+
continue;
135+
}
136+
case Bytecode.DUP: {
137+
int dupValue = getInt(frame, top);
138+
top++;
139+
setInt(frame, top, dupValue);
140+
bci++;
141+
continue;
142+
}
143+
case Bytecode.POP: {
144+
top--;
145+
bci++;
146+
continue;
147+
}
148+
149+
case Bytecode.JMP: {
150+
byte newBci = bytecodes[bci + 1];
151+
bci = newBci;
152+
continue;
153+
}
154+
case Bytecode.IFZERO: {
155+
int value = getInt(frame, top);
156+
top--;
157+
if (value == 0) {
158+
bci = bytecodes[bci + 1];
159+
continue;
160+
} else {
161+
bci = bci + 2;
162+
continue;
163+
}
164+
}
165+
case Bytecode.RETURN: {
166+
int value = getInt(frame, top);
167+
return value;
168+
}
169+
170+
default: {
171+
throw new IllegalStateException();
172+
}
173+
}
174+
}
175+
}
176+
}
177+
178+
@Test
179+
public void constReturnProgram() {
180+
byte[] bytecodes = new byte[]{
181+
/* 0: */Bytecode.CONST,
182+
/* 1: */42,
183+
/* 2: */Bytecode.RETURN};
184+
partialEval(Program.create("constReturnProgram", bytecodes, 2, false));
185+
}
186+
187+
@Test
188+
public void constAddProgram() {
189+
byte[] bytecodes = new byte[]{
190+
/* 0: */Bytecode.CONST,
191+
/* 1: */40,
192+
/* 2: */Bytecode.CONST,
193+
/* 3: */2,
194+
/* 4: */Bytecode.ADD,
195+
/* 5: */Bytecode.RETURN};
196+
partialEval(Program.create("constAddProgram", bytecodes, 2, false));
197+
}
198+
199+
@Test(expected = BailoutException.class)
200+
public void multipleKeyVariables() {
201+
byte[] bytecodes = new byte[]{
202+
/* 0: */Bytecode.CONST,
203+
/* 1: */42,
204+
/* 2: */Bytecode.RETURN};
205+
partialEval(Program.create("multipleKeyVariables", bytecodes, 2, true));
206+
}
207+
208+
@Test(expected = BailoutException.class)
209+
public void variableStackSize() {
210+
byte[] bytecodes = new byte[]{
211+
/* 0: */Bytecode.ARGUMENT,
212+
/* 1: */0,
213+
/* 2: */Bytecode.IFZERO,
214+
/* 3: */6,
215+
/* 4: */Bytecode.CONST,
216+
/* 5: */40,
217+
/* 6: */Bytecode.CONST,
218+
/* 7: */42,
219+
/* 8: */Bytecode.RETURN};
220+
partialEval(Program.create("variableStackSize", bytecodes, 3, false), 0);
221+
}
222+
}

0 commit comments

Comments
 (0)