Skip to content

Commit 6697022

Browse files
committed
[GR-33600] Espresso svm offset recomputation
PullRequest: graal/9709
2 parents 5b743d4 + afb69f0 commit 6697022

File tree

3 files changed

+199
-29
lines changed

3 files changed

+199
-29
lines changed

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import java.util.concurrent.ConcurrentHashMap;
4545
import java.util.function.BooleanSupplier;
4646

47+
import com.oracle.svm.core.config.ConfigurationValues;
48+
import com.oracle.truffle.api.staticobject.StaticProperty;
4749
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
4850
import org.graalvm.compiler.nodes.ConstantNode;
4951
import org.graalvm.compiler.nodes.ValueNode;
@@ -107,6 +109,7 @@
107109
import jdk.vm.ci.meta.MetaAccessProvider;
108110
import jdk.vm.ci.meta.ResolvedJavaField;
109111
import jdk.vm.ci.meta.ResolvedJavaMethod;
112+
import sun.misc.Unsafe;
110113

111114
/**
112115
* Base feature for using Truffle in the SVM. If only this feature is used (not included through
@@ -219,8 +222,9 @@ public void setProfilingEnabled(boolean profilingEnabled) {
219222

220223
@Override
221224
public void cleanup() {
222-
// clean the cached call target nodes to prevent them from keeping application
223-
// classes alive
225+
/*
226+
* Clean the cached call target nodes to prevent them from keeping application classes alive
227+
*/
224228
TruffleRuntime runtime = Truffle.getRuntime();
225229
if (!(runtime instanceof DefaultTruffleRuntime) && !(runtime instanceof SubstrateTruffleRuntime)) {
226230
throw VMError.shouldNotReachHere("Only SubstrateTruffleRuntime and DefaultTruffleRuntime supported");
@@ -512,16 +516,14 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod,
512516

513517
static void duringAnalysis(DuringAnalysisAccess access) {
514518
boolean requiresIteration = false;
515-
// We need to register as unsafe-accessed the primitive, object, and shape
516-
// fields of
517-
// generated storage classes. However, these classes do not share a common super
518-
// type, and their fields are not annotated. Plus, the invocation plugin does
519-
// not
520-
// intercept calls to `StaticShape.Builder.build()` that happen during the
521-
// analysis,
522-
// for example because of context pre-initialization. Therefore, we inspect the
523-
// generator cache in ArrayBasedShapeGenerator, which contains references to all
524-
// generated storage classes.
519+
/*
520+
* We need to register as unsafe-accessed the primitive, object, and shape fields of
521+
* generated storage classes. However, these classes do not share a common super type,
522+
* and their fields are not annotated. Plus, the invocation plugin does not intercept
523+
* calls to `StaticShape.Builder.build()` that happen during the analysis, for example
524+
* because of context pre-initialization. Therefore, we inspect the generator cache in
525+
* ArrayBasedShapeGenerator, which contains references to all generated storage classes.
526+
*/
525527
ConcurrentHashMap<?, ?> generatorCache = ReflectionUtil.readStaticField(SHAPE_GENERATOR, "generatorCache");
526528
for (Map.Entry<?, ?> entry : generatorCache.entrySet()) {
527529
Object shapeGenerator = entry.getValue();
@@ -625,6 +627,82 @@ private static void registerReflectionAccessesForRuntimeValidation(Class<?> stor
625627
}
626628
}
627629

630+
@TargetClass(className = "com.oracle.truffle.api.staticobject.StaticProperty", onlyWith = TruffleBaseFeature.IsEnabled.class)
631+
final class Target_com_oracle_truffle_api_staticobject_StaticProperty {
632+
633+
@Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = Target_com_oracle_truffle_api_staticobject_StaticProperty.OffsetTransformer.class) //
634+
int offset;
635+
636+
public static final class OffsetTransformer implements RecomputeFieldValue.CustomFieldValueTransformer {
637+
/*
638+
* We have to use reflection to access private members instead of aliasing them in the
639+
* substitution class since substitutions are present only at runtime
640+
*/
641+
private static final Method staticPropertyGetInternalKind;
642+
643+
static {
644+
// Checkstyle: stop
645+
staticPropertyGetInternalKind = ReflectionUtil.lookupMethod(StaticProperty.class, "getInternalKindName");
646+
// Checkstyle: resume
647+
}
648+
649+
@Override
650+
public Object transform(MetaAccessProvider metaAccess, ResolvedJavaField original, ResolvedJavaField annotated,
651+
Object receiver, Object originalValue) {
652+
int offset = (int) originalValue;
653+
if (offset == 0) {
654+
/*
655+
* The offset is not yet initialized, probably because no shape was built for the
656+
* receiver static property
657+
*/
658+
return offset;
659+
}
660+
661+
StaticProperty receiverStaticProperty = (StaticProperty) receiver;
662+
663+
String internalKindName;
664+
try {
665+
// Checkstyle: stop
666+
internalKindName = (String) staticPropertyGetInternalKind.invoke(receiverStaticProperty);
667+
// Checkstyle: resume
668+
} catch (IllegalAccessException | InvocationTargetException e) {
669+
throw VMError.shouldNotReachHere(e);
670+
}
671+
672+
int baseOffset;
673+
int indexScale;
674+
JavaKind javaKind;
675+
if (internalKindName.equals("Object")) {
676+
javaKind = JavaKind.Object;
677+
baseOffset = Unsafe.ARRAY_OBJECT_BASE_OFFSET;
678+
indexScale = Unsafe.ARRAY_OBJECT_INDEX_SCALE;
679+
} else {
680+
javaKind = JavaKind.Byte;
681+
baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
682+
indexScale = Unsafe.ARRAY_BYTE_INDEX_SCALE;
683+
}
684+
685+
assert offset >= baseOffset && (offset - baseOffset) % indexScale == 0;
686+
687+
/*
688+
* Reverse the offset computation to find the index
689+
*/
690+
int index = (offset - baseOffset) / indexScale;
691+
692+
/*
693+
* Find SVM array base offset and array index scale for this JavaKind
694+
*/
695+
int svmArrayBaseOffset = ConfigurationValues.getObjectLayout().getArrayBaseOffset(javaKind);
696+
int svmArrayIndexScaleOffset = ConfigurationValues.getObjectLayout().getArrayIndexScale(javaKind);
697+
698+
/*
699+
* Redo the offset computation with the SVM array base offset and array index scale
700+
*/
701+
return svmArrayBaseOffset + svmArrayIndexScaleOffset * index;
702+
}
703+
}
704+
}
705+
628706
@TargetClass(className = "com.oracle.truffle.api.staticobject.ArrayBasedShapeGenerator", onlyWith = TruffleBaseFeature.IsEnabled.class)
629707
final class Target_com_oracle_truffle_api_staticobject_ArrayBasedShapeGenerator {
630708

@@ -676,22 +754,22 @@ public Object transform(MetaAccessProvider metaAccess, ResolvedJavaField origina
676754

677755
// Checkstyle: stop
678756

679-
// If allowProcess() is disabled at build time, then we ensure that
680-
// ProcessBuilder is not reachable.
681-
// The main purpose of this is to test that ProcessBuilder is not part of the
682-
// image when building
683-
// language images with allowProcess() disabled, which we interpret as "forbid
684-
// shelling out to
685-
// external processes" (GR-14041).
757+
/*
758+
* If allowProcess() is disabled at build time, then we ensure that ProcessBuilder is not reachable.
759+
* The main purpose of this is to test that ProcessBuilder is not part of the image when building
760+
* language images with allowProcess() disabled, which we interpret as
761+
* "forbid shelling out to external processes" (GR-14041).
762+
*/
686763
@Delete
687764
@TargetClass(className = "java.lang.ProcessBuilder", onlyWith = {TruffleBaseFeature.IsEnabled.class,
688765
TruffleBaseFeature.IsCreateProcessDisabled.class})
689766
final class Target_java_lang_ProcessBuilder {
690767
}
691768

692-
// If allowProcess() is disabled at build time, then we ensure
693-
// ObjdumpDisassemblerProvider does not
694-
// try to invoke the nonexistent ProcessBuilder.
769+
/*
770+
* If allowProcess() is disabled at build time, then we ensure ObjdumpDisassemblerProvider does not
771+
* try to invoke the nonexistent ProcessBuilder.
772+
*/
695773
@TargetClass(className = "org.graalvm.compiler.code.ObjdumpDisassemblerProvider", onlyWith = {
696774
TruffleBaseFeature.IsEnabled.class, TruffleBaseFeature.IsCreateProcessDisabled.class})
697775
final class Target_org_graalvm_compiler_code_ObjdumpDisassemblerProvider {

truffle/src/com.oracle.truffle.api.staticobject.test/src/com/oracle/truffle/api/staticobject/test/StaticTest.java

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,112 @@
5353
* built time for context pre-initialization.
5454
*/
5555
public class StaticTest {
56-
private static final StaticProperty property;
56+
private static final StaticProperty propertyB;
57+
private static final StaticProperty propertyS;
58+
private static final StaticProperty propertyC;
59+
private static final StaticProperty propertyI;
60+
private static final StaticProperty propertyL;
61+
private static final StaticProperty propertyF;
62+
private static final StaticProperty propertyD;
63+
private static final StaticProperty propertyTF;
64+
private static final StaticProperty propertyO1;
65+
private static final StaticProperty propertyO2;
5766
private static final Object staticObject;
67+
private static final byte testValueB = 1;
68+
private static final short testValueS = 2;
69+
private static final char testValueC = 'a';
70+
private static final int testValueI = 3;
71+
private static final long testValueL = 4;
72+
private static final float testValueF = 5.0f;
73+
private static final double testValueD = 6.0;
74+
private static final boolean testValueTF = true;
75+
private static final Object testValueO1 = "object1";
76+
private static final Object testValueO2 = "object2";
5877

5978
static {
6079
TestEnvironment environment = new TestEnvironment(new TestConfiguration(true, false));
6180
StaticShape.Builder builder = StaticShape.newBuilder(environment.testLanguage);
62-
property = new DefaultStaticProperty("property");
63-
builder.property(property, int.class, false);
81+
propertyB = new DefaultStaticProperty("propertyB");
82+
propertyS = new DefaultStaticProperty("propertyS");
83+
propertyC = new DefaultStaticProperty("propertyC");
84+
propertyI = new DefaultStaticProperty("propertyI");
85+
propertyL = new DefaultStaticProperty("propertyL");
86+
propertyF = new DefaultStaticProperty("propertyF");
87+
propertyD = new DefaultStaticProperty("propertyD");
88+
propertyTF = new DefaultStaticProperty("propertyTF");
89+
propertyO1 = new DefaultStaticProperty("propertyO1");
90+
propertyO2 = new DefaultStaticProperty("propertyO2");
91+
builder.property(propertyB, byte.class, false);
92+
builder.property(propertyS, short.class, false);
93+
builder.property(propertyC, char.class, false);
94+
builder.property(propertyI, int.class, false);
95+
builder.property(propertyL, long.class, false);
96+
builder.property(propertyF, float.class, false);
97+
builder.property(propertyD, double.class, false);
98+
builder.property(propertyTF, boolean.class, false);
99+
builder.property(propertyO1, Object.class, false);
100+
builder.property(propertyO2, Object.class, false);
64101
staticObject = builder.build().getFactory().create();
65-
property.setInt(staticObject, 42);
102+
propertyB.setByte(staticObject, testValueB);
103+
propertyS.setShort(staticObject, testValueS);
104+
propertyC.setChar(staticObject, testValueC);
105+
propertyI.setInt(staticObject, testValueI);
106+
propertyL.setLong(staticObject, testValueL);
107+
propertyF.setFloat(staticObject, testValueF);
108+
propertyD.setDouble(staticObject, testValueD);
109+
propertyTF.setBoolean(staticObject, testValueTF);
110+
propertyO1.setObject(staticObject, testValueO1);
111+
propertyO2.setObject(staticObject, testValueO2);
66112
}
67113

68114
@Test
69115
public void staticallyDeclaredStaticObject() {
70-
Assert.assertEquals(42, property.getInt(staticObject));
71-
property.setInt(staticObject, 24);
72-
Assert.assertEquals(24, property.getInt(staticObject));
116+
Assert.assertEquals(testValueB, propertyB.getByte(staticObject));
117+
Assert.assertEquals(testValueS, propertyS.getShort(staticObject));
118+
Assert.assertEquals(testValueC, propertyC.getChar(staticObject));
119+
Assert.assertEquals(testValueI, propertyI.getInt(staticObject));
120+
Assert.assertEquals(testValueL, propertyL.getLong(staticObject));
121+
Assert.assertEquals(testValueF, propertyF.getFloat(staticObject), 1e-6f);
122+
Assert.assertEquals(testValueD, propertyD.getDouble(staticObject), 1e-6);
123+
Assert.assertEquals(testValueTF, propertyTF.getBoolean(staticObject));
124+
Assert.assertEquals(testValueO1, propertyO1.getObject(staticObject));
125+
Assert.assertEquals(testValueO2, propertyO2.getObject(staticObject));
126+
127+
byte newTestValueB = 11;
128+
propertyB.setByte(staticObject, newTestValueB);
129+
Assert.assertEquals(newTestValueB, propertyB.getByte(staticObject));
130+
131+
short newTestValueS = 22;
132+
propertyS.setShort(staticObject, newTestValueS);
133+
Assert.assertEquals(newTestValueS, propertyS.getShort(staticObject));
134+
135+
char newTestValueC = 'b';
136+
propertyC.setChar(staticObject, newTestValueC);
137+
Assert.assertEquals(newTestValueC, propertyC.getChar(staticObject));
138+
139+
int newTestValueI = 33;
140+
propertyI.setInt(staticObject, newTestValueI);
141+
Assert.assertEquals(newTestValueI, propertyI.getInt(staticObject));
142+
143+
long newTestValueL = 44;
144+
propertyL.setLong(staticObject, newTestValueL);
145+
Assert.assertEquals(newTestValueL, propertyL.getLong(staticObject));
146+
147+
float newTestValueF = 55.0f;
148+
propertyF.setFloat(staticObject, newTestValueF);
149+
Assert.assertEquals(newTestValueF, propertyF.getFloat(staticObject), 1e-6f);
150+
151+
double newTestValueD = 66.0;
152+
propertyD.setDouble(staticObject, newTestValueD);
153+
Assert.assertEquals(newTestValueD, propertyD.getDouble(staticObject), 1e-6);
154+
155+
propertyTF.setBoolean(staticObject, false);
156+
Assert.assertFalse(propertyTF.getBoolean(staticObject));
157+
158+
Object newTestValueO = "object3";
159+
propertyO1.setObject(staticObject, newTestValueO);
160+
Assert.assertEquals(newTestValueO, propertyO1.getObject(staticObject));
161+
propertyO2.setObject(staticObject, newTestValueO);
162+
Assert.assertEquals(newTestValueO, propertyO2.getObject(staticObject));
73163
}
74164
}

truffle/src/com.oracle.truffle.api.staticobject/src/com/oracle/truffle/api/staticobject/ArrayBasedStaticShape.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ static class ArrayBasedPropertyLayout {
225225
byte propertyKind = staticProperty.getInternalKind();
226226
int index;
227227
if (propertyKind == StaticPropertyKind.Object.toByte()) {
228+
// These offsets are re-computed for SVM:
229+
// TruffleBaseFeature.Target_com_oracle_truffle_api_staticobject_StaticProperty
228230
index = Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * objArraySize++;
229231
} else {
230232
index = primitiveFieldIndexes.getIndex(propertyKind);

0 commit comments

Comments
 (0)