Skip to content

Commit 1e0b993

Browse files
committed
[GR-57063] Implement improved variadic support for the Bytecode DSL.
PullRequest: graal/20274
2 parents 1cca4db + 680631a commit 1e0b993

File tree

19 files changed

+1639
-374
lines changed

19 files changed

+1639
-374
lines changed

truffle/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ This changelog summarizes major changes between Truffle versions relevant to lan
55
## Version 25.0
66
* GR-31495 Added ability to specify language and instrument specific options using `Source.Builder.option(String, String)`. Languages may describe available source options by implementing `TruffleLanguage.getSourceOptionDescriptors()` and `TruffleInstrument.getSourceOptionDescriptors()` respectively.
77
* GR-61493 Added `RootNode.prepareForCall` which allows root nodes to prepare themselves for use as a call target (or to validate whether they can be used as a call target).
8+
* GR-57063 Bytecode-DSL: Improved variadic support. Variadic operands compile and execute now more efficiently with fewer reallocations.
9+
* GR-57063 Bytecode-DSL: Added an `startOffset` parameter to `@Variadic` which allows to reserve a fixed number of slots in the object array for custom use.
10+
* GR-57063 Bytecode-DSL: The `@Variadic` annotation can now also be used on `@Operation` annotated classes to indicate that the operation produces a dynamic variadic return value. Dynamic variadic return values are efficiently flattened into the object array of a variadic operand.
11+
* GR-57063 Bytecode-DSL: Added a `variadicStackLimit` parameter to `@GenerateBytecode` that allows to specify how many variable arguments are stored on the stack before they are collapsed into an object array.
812

913
## Version 24.2.0
1014
* GR-60636 Truffle now stops compiling when the code cache fills up on HotSpot. A warning is printed when that happens.

truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/VariadicTest.java

-156
This file was deleted.

truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/basic_interpreter/AbstractBasicInterpreterTest.java

+36
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import org.junit.runners.Parameterized.Parameter;
6969
import org.junit.runners.Parameterized.Parameters;
7070

71+
import com.oracle.truffle.api.CompilerDirectives;
7172
import com.oracle.truffle.api.RootCallTarget;
7273
import com.oracle.truffle.api.bytecode.BytecodeConfig;
7374
import com.oracle.truffle.api.bytecode.BytecodeLabel;
@@ -112,6 +113,11 @@ public boolean hasUncachedInterpreter() {
112113
interpreterClass == BasicInterpreterProductionRootScoping.class;
113114
}
114115

116+
@SuppressWarnings("static-method")
117+
public boolean hasYield() {
118+
return true;
119+
}
120+
115121
public boolean hasRootScoping() {
116122
return interpreterClass == BasicInterpreterWithRootScoping.class ||
117123
interpreterClass == BasicInterpreterProductionRootScoping.class;
@@ -130,6 +136,36 @@ public String toString() {
130136
return interpreterClass.getSimpleName() + "[serialize=" + testSerialize + "]";
131137
}
132138

139+
public int getFrameBaseSlots() {
140+
int baseCount = 0;
141+
if (hasUncachedInterpreter() || storesBciInFrame()) {
142+
baseCount++; // bci
143+
}
144+
if (hasYield()) {
145+
baseCount++;
146+
}
147+
return baseCount;
148+
}
149+
150+
@SuppressWarnings("static-method")
151+
public int getVariadicsLimit() {
152+
if (interpreterClass == BasicInterpreterBase.class //
153+
|| interpreterClass == BasicInterpreterWithBE.class //
154+
|| interpreterClass == BasicInterpreterWithStoreBytecodeIndexInFrame.class) {
155+
return 4;
156+
} else if (interpreterClass == BasicInterpreterUnsafe.class //
157+
|| interpreterClass == BasicInterpreterWithOptimizations.class //
158+
|| interpreterClass == BasicInterpreterProductionBlockScoping.class) {
159+
return 8;
160+
} else if (interpreterClass == BasicInterpreterWithUncached.class //
161+
|| interpreterClass == BasicInterpreterWithRootScoping.class //
162+
|| interpreterClass == BasicInterpreterProductionRootScoping.class) {
163+
return 16;
164+
}
165+
166+
throw CompilerDirectives.shouldNotReachHere();
167+
}
168+
133169
public Object getDefaultLocalValue() {
134170
if (interpreterClass == BasicInterpreterWithOptimizations.class || interpreterClass == BasicInterpreterWithRootScoping.class) {
135171
return BasicInterpreter.LOCAL_DEFAULT_VALUE;

truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/basic_interpreter/BasicInterpreter.java

+74-9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
*/
4141
package com.oracle.truffle.api.bytecode.test.basic_interpreter;
4242

43+
import static org.junit.Assert.assertNull;
44+
import static org.junit.Assert.assertTrue;
45+
4346
import java.util.ArrayList;
4447
import java.util.List;
4548

@@ -104,43 +107,49 @@
104107
enableSerialization = true, //
105108
enableTagInstrumentation = true, //
106109
enableSpecializationIntrospection = true, //
107-
allowUnsafe = false)),
110+
allowUnsafe = false, //
111+
variadicStackLimit = "4")),
108112
@Variant(suffix = "Unsafe", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
109113
enableYield = true, //
110114
enableMaterializedLocalAccesses = true, //
111115
enableSerialization = true, //
112116
enableTagInstrumentation = true, //
113-
enableSpecializationIntrospection = true)),
117+
enableSpecializationIntrospection = true, //
118+
variadicStackLimit = "8")),
114119
@Variant(suffix = "WithUncached", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
115120
enableYield = true, //
116121
enableMaterializedLocalAccesses = true, //
117122
enableSerialization = true, //
118123
enableTagInstrumentation = true, //
119124
enableUncachedInterpreter = true, //
120125
defaultUncachedThreshold = "defaultUncachedThreshold", //
121-
enableSpecializationIntrospection = true)),
126+
enableSpecializationIntrospection = true, //
127+
variadicStackLimit = "16")),
122128
@Variant(suffix = "WithBE", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
123129
enableYield = true, //
124130
enableMaterializedLocalAccesses = true, //
125131
enableSerialization = true, //
126132
enableTagInstrumentation = true, //
127133
enableSpecializationIntrospection = true, //
128-
boxingEliminationTypes = {boolean.class, long.class})),
134+
boxingEliminationTypes = {boolean.class, long.class}, //
135+
variadicStackLimit = "4")),
129136
@Variant(suffix = "WithOptimizations", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
130137
enableYield = true, //
131138
enableMaterializedLocalAccesses = true, //
132139
enableSerialization = true, //
133140
enableSpecializationIntrospection = true, //
134141
enableTagInstrumentation = true, //
135-
defaultLocalValue = "LOCAL_DEFAULT_VALUE")),
142+
defaultLocalValue = "LOCAL_DEFAULT_VALUE", //
143+
variadicStackLimit = "8")),
136144
@Variant(suffix = "WithRootScoping", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
137145
enableYield = true, //
138146
enableMaterializedLocalAccesses = true, //
139147
enableSerialization = true, //
140148
enableBlockScoping = false, //
141149
enableTagInstrumentation = true, //
142150
enableSpecializationIntrospection = true, //
143-
defaultLocalValue = "LOCAL_DEFAULT_VALUE")),
151+
defaultLocalValue = "LOCAL_DEFAULT_VALUE", //
152+
variadicStackLimit = "16")),
144153
@Variant(suffix = "WithStoreBytecodeIndexInFrame", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
145154
enableYield = true, //
146155
enableMaterializedLocalAccesses = true, //
@@ -150,7 +159,8 @@
150159
enableSpecializationIntrospection = true, //
151160
boxingEliminationTypes = {boolean.class, long.class}, //
152161
storeBytecodeIndexInFrame = true, //
153-
enableTagInstrumentation = true)),
162+
enableTagInstrumentation = true, //
163+
variadicStackLimit = "4")),
154164
// A typical "production" configuration with all of the bells and whistles.
155165
@Variant(suffix = "ProductionBlockScoping", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
156166
enableYield = true, //
@@ -160,7 +170,8 @@
160170
enableUncachedInterpreter = true, //
161171
defaultUncachedThreshold = "defaultUncachedThreshold", //
162172
enableSpecializationIntrospection = true, //
163-
boxingEliminationTypes = {boolean.class, long.class})),
173+
boxingEliminationTypes = {boolean.class, long.class}, //
174+
variadicStackLimit = "8")),
164175
@Variant(suffix = "ProductionRootScoping", configuration = @GenerateBytecode(languageClass = BytecodeDSLTestLanguage.class, //
165176
enableYield = true, //
166177
enableMaterializedLocalAccesses = true, //
@@ -170,7 +181,8 @@
170181
enableUncachedInterpreter = true, //
171182
defaultUncachedThreshold = "defaultUncachedThreshold", //
172183
enableSpecializationIntrospection = true, //
173-
boxingEliminationTypes = {boolean.class, long.class}))
184+
boxingEliminationTypes = {boolean.class, long.class}, //
185+
variadicStackLimit = "16"))
174186
})
175187
@ShortCircuitOperation(booleanConverter = BasicInterpreter.ToBoolean.class, name = "ScAnd", operator = Operator.AND_RETURN_VALUE)
176188
@ShortCircuitOperation(booleanConverter = BasicInterpreter.ToBoolean.class, name = "ScOr", operator = Operator.OR_RETURN_VALUE, javadoc = "ScOr returns the first truthy operand value.")
@@ -884,6 +896,59 @@ public static Bindings doDefault(
884896
return new Bindings(bytecode, root1, location, instruction, node, bytecodeIndex);
885897
}
886898
}
899+
900+
@Operation
901+
static final class Variadic0Operation {
902+
@Specialization
903+
public static Object[] variadic(@Variadic Object[] args) {
904+
return args;
905+
}
906+
}
907+
908+
@Operation
909+
static final class Variadic1Operation {
910+
@Specialization
911+
@SuppressWarnings("unused")
912+
public static Object[] variadic(long arg0, @Variadic Object[] args) {
913+
return args;
914+
}
915+
}
916+
917+
@Operation
918+
static final class VariadicOffsetOperation {
919+
@Specialization
920+
@SuppressWarnings("unused")
921+
public static Object[] variadic(@Variadic(startOffset = 4) Object[] args) {
922+
assertTrue(args.length >= 3);
923+
for (int i = 0; i < 4; i++) {
924+
assertNull(args[i]);
925+
}
926+
return args;
927+
}
928+
}
929+
930+
@Operation
931+
@Variadic
932+
static final class DynamicVariadic {
933+
934+
@Specialization
935+
@SuppressWarnings("unused")
936+
public static Object[] pass(@Variadic Object[] args) {
937+
return args;
938+
}
939+
}
940+
941+
@Operation
942+
@Variadic
943+
static final class DynamicVariadicNull {
944+
945+
@Specialization
946+
@SuppressWarnings("unused")
947+
public static Object[] pass() {
948+
return null;
949+
}
950+
}
951+
887952
}
888953

889954
class TestClosure {

0 commit comments

Comments
 (0)