Skip to content

Commit 3dffe98

Browse files
committed
Omit receiver type check.
1 parent ec2d80c commit 3dffe98

File tree

3 files changed

+68
-25
lines changed

3 files changed

+68
-25
lines changed

truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/FieldInfo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import java.lang.invoke.VarHandle;
4444
import java.lang.reflect.Field;
45+
import java.util.Objects;
4546

4647
import com.oracle.truffle.api.CompilerAsserts;
4748
import com.oracle.truffle.api.CompilerDirectives;
@@ -158,4 +159,12 @@ private IllegalArgumentException illegalReceiver(DynamicObject store) {
158159
CompilerAsserts.neverPartOfCompilation();
159160
return new IllegalArgumentException("Invalid receiver type (expected " + getDeclaringClass() + ", was " + (store == null ? null : store.getClass()) + ")");
160161
}
162+
163+
DynamicObject unsafeReceiverCast(DynamicObject store) {
164+
if (ObjectStorageOptions.ReceiverCast) {
165+
return Objects.requireNonNull(tclass.cast(store));
166+
} else {
167+
return store;
168+
}
169+
}
161170
}

truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Location.java

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -201,26 +201,28 @@ protected double getDouble(DynamicObject store, boolean guard) throws Unexpected
201201
* @param guard the result of the shape check or {@code false}
202202
* @return the read value
203203
*/
204+
@SuppressWarnings("hiding")
204205
final Object getInternal(DynamicObject store, Shape expectedShape, boolean guard) {
206+
DynamicObject receiver = unsafeNonNullCast(store);
205207
long idx = Integer.toUnsignedLong(index);
208+
FieldInfo field = this.field;
206209
if (this instanceof ObjectLocation objectLocation) {
207210
Object base;
208211
long offset;
209212
Object value;
210213
if (field == null) {
211-
base = getObjectArray(store, guard);
214+
base = getObjectArray(receiver, guard);
212215
offset = computeObjectArrayOffset(idx);
213216
value = UnsafeAccess.unsafeGetObject(base, offset, guard, this);
214217
} else {
215-
field.receiverCheck(store);
216-
base = store;
218+
base = field.unsafeReceiverCast(receiver);
217219
offset = getFieldOffset();
218220
value = UnsafeAccess.unsafeGetObject(base, offset, guard, this);
219221
}
220222
return CompilerDirectives.inInterpreter() ? value : objectLocation.assumedTypeCast(value, guard);
221223
} else {
222224
if (field == null) {
223-
Object array = getPrimitiveArray(store, guard);
225+
Object array = getPrimitiveArray(receiver, guard);
224226
long offset = computePrimitiveArrayOffset(idx);
225227
if (isIntLocation()) {
226228
return UnsafeAccess.unsafeGetInt(array, offset, guard, this);
@@ -229,11 +231,11 @@ final Object getInternal(DynamicObject store, Shape expectedShape, boolean guard
229231
} else if (isDoubleLocation()) {
230232
return UnsafeAccess.unsafeGetDouble(array, offset, guard, this);
231233
} else {
232-
return ((ConstantLocation) this).get(store, guard);
234+
return ((ConstantLocation) this).get(receiver, guard);
233235
}
234236
} else {
235-
field.receiverCheck(store);
236-
long longValue = UnsafeAccess.unsafeGetLong(store, getFieldOffset(), guard, this);
237+
Object base = field.unsafeReceiverCast(receiver);
238+
long longValue = UnsafeAccess.unsafeGetLong(base, getFieldOffset(), guard, this);
237239
if (this instanceof IntLocation) {
238240
return (int) longValue;
239241
} else if (this instanceof LongLocation) {
@@ -250,18 +252,19 @@ final Object getInternal(DynamicObject store, Shape expectedShape, boolean guard
250252
* @see #getInternal(DynamicObject, Shape, boolean)
251253
*/
252254
final int getIntInternal(DynamicObject store, Shape expectedShape, boolean guard) throws UnexpectedResultException {
255+
DynamicObject receiver = unsafeNonNullCast(store);
253256
if (isIntLocation()) {
254257
if (field == null) {
255-
Object array = getPrimitiveArray(store, guard);
258+
Object array = getPrimitiveArray(receiver, guard);
256259
long offset = getPrimitiveArrayOffset();
257260
return UnsafeAccess.unsafeGetInt(array, offset, guard, this);
258261
} else {
259-
field.receiverCheck(store);
260-
long longValue = UnsafeAccess.unsafeGetLong(store, getFieldOffset(), guard, this);
262+
Object base = field.unsafeReceiverCast(receiver);
263+
long longValue = UnsafeAccess.unsafeGetLong(base, getFieldOffset(), guard, this);
261264
return (int) longValue;
262265
}
263266
}
264-
return getIntUnexpected(store, expectedShape, guard);
267+
return getIntUnexpected(receiver, expectedShape, guard);
265268
}
266269

267270
/**
@@ -277,17 +280,18 @@ private int getIntUnexpected(DynamicObject store, Shape expectedShape, boolean g
277280
* @see #getInternal(DynamicObject, Shape, boolean)
278281
*/
279282
final long getLongInternal(DynamicObject store, Shape expectedShape, boolean guard) throws UnexpectedResultException {
283+
DynamicObject receiver = unsafeNonNullCast(store);
280284
if (isLongLocation()) {
281285
if (field == null) {
282-
Object array = getPrimitiveArray(store, guard);
286+
Object array = getPrimitiveArray(receiver, guard);
283287
long offset = getPrimitiveArrayOffset();
284288
return UnsafeAccess.unsafeGetLong(array, offset, guard, this);
285289
} else {
286-
field.receiverCheck(store);
287-
return UnsafeAccess.unsafeGetLong(store, getFieldOffset(), guard, this);
290+
Object base = field.unsafeReceiverCast(receiver);
291+
return UnsafeAccess.unsafeGetLong(base, getFieldOffset(), guard, this);
288292
}
289293
}
290-
return getLongUnexpected(store, expectedShape, guard);
294+
return getLongUnexpected(receiver, expectedShape, guard);
291295
}
292296

293297
/**
@@ -303,18 +307,19 @@ private long getLongUnexpected(DynamicObject store, Shape expectedShape, boolean
303307
* @see #getInternal(DynamicObject, Shape, boolean)
304308
*/
305309
final double getDoubleInternal(DynamicObject store, Shape expectedShape, boolean guard) throws UnexpectedResultException {
310+
DynamicObject receiver = unsafeNonNullCast(store);
306311
if (isDoubleLocation()) {
307312
if (field == null) {
308-
Object array = getPrimitiveArray(store, guard);
313+
Object array = getPrimitiveArray(receiver, guard);
309314
long offset = getPrimitiveArrayOffset();
310315
return UnsafeAccess.unsafeGetDouble(array, offset, guard, this);
311316
} else {
312-
field.receiverCheck(store);
313-
long longValue = UnsafeAccess.unsafeGetLong(store, getFieldOffset(), guard, this);
317+
Object base = field.unsafeReceiverCast(receiver);
318+
long longValue = UnsafeAccess.unsafeGetLong(base, getFieldOffset(), guard, this);
314319
return Double.longBitsToDouble(longValue);
315320
}
316321
}
317-
return getDoubleUnexpected(store, expectedShape, guard);
322+
return getDoubleUnexpected(receiver, expectedShape, guard);
318323
}
319324

320325
/**
@@ -436,16 +441,19 @@ final void setDoubleSafe(DynamicObject store, double value, boolean guard, boole
436441
* Stores a value in this location. Grows the object if necessary. It is the caller's
437442
* responsibility to check that the value is compatible with this location first.
438443
*
439-
* @param receiver storage object
444+
* @param store storage object
440445
* @param value the value to be stored
441446
* @param guard the result of the shape check guarding this property write or {@code false}
442447
* @param oldShape the expected shape before the set
443448
* @param newShape the expected shape after the set
444449
* @see #canStoreValue(Object).
445450
*/
446-
final void setInternal(DynamicObject receiver, Object value, boolean guard, Shape oldShape, Shape newShape) {
451+
@SuppressWarnings("hiding")
452+
final void setInternal(DynamicObject store, Object value, boolean guard, Shape oldShape, Shape newShape) {
447453
assert canStoreValue(value) : value;
454+
DynamicObject receiver = unsafeNonNullCast(store);
448455
long idx = Integer.toUnsignedLong(index);
456+
FieldInfo field = this.field;
449457
boolean init = newShape != oldShape;
450458
if (init) {
451459
DynamicObjectSupport.grow(receiver, oldShape, newShape);
@@ -467,8 +475,7 @@ final void setInternal(DynamicObject receiver, Object value, boolean guard, Shap
467475
offset = computeObjectArrayOffset(idx);
468476
UnsafeAccess.unsafePutObject(base, offset, value, this);
469477
} else {
470-
field.receiverCheck(receiver);
471-
base = receiver;
478+
base = field.unsafeReceiverCast(receiver);
472479
offset = getFieldOffset();
473480
UnsafeAccess.unsafePutObject(base, offset, value, this);
474481
}
@@ -519,9 +526,23 @@ final void setInternal(DynamicObject receiver, Object value, boolean guard, Shap
519526
assert isConstantLocation() : this;
520527
return;
521528
}
522-
field.receiverCheck(receiver);
529+
Object base = field.unsafeReceiverCast(receiver);
523530
long offset = getFieldOffset();
524-
UnsafeAccess.unsafePutLong(receiver, offset, longValue, this);
531+
UnsafeAccess.unsafePutLong(base, offset, longValue, this);
532+
}
533+
}
534+
535+
private static DynamicObject unsafeNonNullCast(DynamicObject receiver) {
536+
/*
537+
* The shape check already performs an implicit null check, so the receiver is guaranteed to
538+
* be non-null here, but when compiling methods separately we might not know this yet.
539+
* Hence, we use an unsafe cast in the interpreter to avoid compiling any null code paths.
540+
* In PE OTOH, the redundant ValueAnchor+Pi would just mean extra work for the compiler.
541+
*/
542+
if (CompilerDirectives.inCompiledCode() || ObjectStorageOptions.ReceiverCast) {
543+
return receiver;
544+
} else {
545+
return UnsafeAccess.hostUnsafeCast(receiver, DynamicObject.class, false, true, false);
525546
}
526547
}
527548

truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObjectStorageOptions.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ final class ObjectStorageOptions {
4747
private ObjectStorageOptions() {
4848
}
4949

50+
static final boolean ASSERTIONS_ENABLED = assertionsEnabled();
51+
5052
static final boolean PrimitiveLocations = booleanOption(OPTION_PREFIX + "PrimitiveLocations", true);
5153
static final boolean IntegerLocations = booleanOption(OPTION_PREFIX + "IntegerLocations", true);
5254
static final boolean DoubleLocations = booleanOption(OPTION_PREFIX + "DoubleLocations", true);
@@ -61,6 +63,10 @@ private ObjectStorageOptions() {
6163
* If set to true, use VarHandle rather than Unsafe to implement field accesses.
6264
*/
6365
static final boolean UseVarHandle = booleanOption(OPTION_PREFIX + "UseVarHandle", false);
66+
/**
67+
* Enforce receiver type checks for unsafe field accesses.
68+
*/
69+
static final boolean ReceiverCast = booleanOption(OPTION_PREFIX + "ReceiverCast", false) || ASSERTIONS_ENABLED;
6470

6571
static final boolean TriePropertyMap = booleanOption(OPTION_PREFIX + "TriePropertyMap", true);
6672
static final boolean TrieTransitionMap = booleanOption(OPTION_PREFIX + "TrieTransitionMap", true);
@@ -94,4 +100,11 @@ static boolean booleanOption(String name, boolean defaultValue) {
94100
String value = System.getProperty(name);
95101
return value == null ? defaultValue : value.equalsIgnoreCase("true");
96102
}
103+
104+
@SuppressWarnings("all")
105+
private static boolean assertionsEnabled() {
106+
boolean enabled = false;
107+
assert (enabled = true) == true;
108+
return enabled;
109+
}
97110
}

0 commit comments

Comments
 (0)