4343import java .util .Objects ;
4444import java .util .concurrent .atomic .AtomicReferenceFieldUpdater ;
4545
46+ import org .graalvm .nativeimage .ImageInfo ;
47+
4648import com .oracle .truffle .api .Assumption ;
4749import com .oracle .truffle .api .CompilerAsserts ;
4850import com .oracle .truffle .api .CompilerDirectives ;
@@ -201,26 +203,28 @@ protected double getDouble(DynamicObject store, boolean guard) throws Unexpected
201203 * @param guard the result of the shape check or {@code false}
202204 * @return the read value
203205 */
206+ @ SuppressWarnings ("hiding" )
204207 final Object getInternal (DynamicObject store , Shape expectedShape , boolean guard ) {
208+ DynamicObject receiver = unsafeNonNullCast (store );
205209 long idx = Integer .toUnsignedLong (index );
210+ FieldInfo field = this .field ;
206211 if (this instanceof ObjectLocation objectLocation ) {
207212 Object base ;
208213 long offset ;
209214 Object value ;
210215 if (field == null ) {
211- base = getObjectArray (store , guard );
216+ base = getObjectArray (receiver , guard );
212217 offset = computeObjectArrayOffset (idx );
213218 value = UnsafeAccess .unsafeGetObject (base , offset , guard , this );
214219 } else {
215- field .receiverCheck (store );
216- base = store ;
217- offset = getFieldOffset ();
220+ base = field .unsafeReceiverCast (receiver );
221+ offset = field .offset ();
218222 value = UnsafeAccess .unsafeGetObject (base , offset , guard , this );
219223 }
220224 return CompilerDirectives .inInterpreter () ? value : objectLocation .assumedTypeCast (value , guard );
221225 } else {
222226 if (field == null ) {
223- Object array = getPrimitiveArray (store , guard );
227+ Object array = getPrimitiveArray (receiver , guard );
224228 long offset = computePrimitiveArrayOffset (idx );
225229 if (isIntLocation ()) {
226230 return UnsafeAccess .unsafeGetInt (array , offset , guard , this );
@@ -229,11 +233,11 @@ final Object getInternal(DynamicObject store, Shape expectedShape, boolean guard
229233 } else if (isDoubleLocation ()) {
230234 return UnsafeAccess .unsafeGetDouble (array , offset , guard , this );
231235 } else {
232- return ((ConstantLocation ) this ).get (store , guard );
236+ return ((ConstantLocation ) this ).get (receiver , guard );
233237 }
234238 } else {
235- field .receiverCheck ( store );
236- long longValue = UnsafeAccess .unsafeGetLong (store , getFieldOffset (), guard , this );
239+ Object base = field .unsafeReceiverCast ( receiver );
240+ long longValue = UnsafeAccess .unsafeGetLong (base , field . offset (), guard , this );
237241 if (this instanceof IntLocation ) {
238242 return (int ) longValue ;
239243 } else if (this instanceof LongLocation ) {
@@ -250,18 +254,19 @@ final Object getInternal(DynamicObject store, Shape expectedShape, boolean guard
250254 * @see #getInternal(DynamicObject, Shape, boolean)
251255 */
252256 final int getIntInternal (DynamicObject store , Shape expectedShape , boolean guard ) throws UnexpectedResultException {
257+ DynamicObject receiver = unsafeNonNullCast (store );
253258 if (isIntLocation ()) {
254259 if (field == null ) {
255- Object array = getPrimitiveArray (store , guard );
260+ Object array = getPrimitiveArray (receiver , guard );
256261 long offset = getPrimitiveArrayOffset ();
257262 return UnsafeAccess .unsafeGetInt (array , offset , guard , this );
258263 } else {
259- field .receiverCheck ( store );
260- long longValue = UnsafeAccess .unsafeGetLong (store , getFieldOffset (), guard , this );
264+ Object base = field .unsafeReceiverCast ( receiver );
265+ long longValue = UnsafeAccess .unsafeGetLong (base , field . offset (), guard , this );
261266 return (int ) longValue ;
262267 }
263268 }
264- return getIntUnexpected (store , expectedShape , guard );
269+ return getIntUnexpected (receiver , expectedShape , guard );
265270 }
266271
267272 /**
@@ -277,17 +282,18 @@ private int getIntUnexpected(DynamicObject store, Shape expectedShape, boolean g
277282 * @see #getInternal(DynamicObject, Shape, boolean)
278283 */
279284 final long getLongInternal (DynamicObject store , Shape expectedShape , boolean guard ) throws UnexpectedResultException {
285+ DynamicObject receiver = unsafeNonNullCast (store );
280286 if (isLongLocation ()) {
281287 if (field == null ) {
282- Object array = getPrimitiveArray (store , guard );
288+ Object array = getPrimitiveArray (receiver , guard );
283289 long offset = getPrimitiveArrayOffset ();
284290 return UnsafeAccess .unsafeGetLong (array , offset , guard , this );
285291 } else {
286- field .receiverCheck ( store );
287- return UnsafeAccess .unsafeGetLong (store , getFieldOffset (), guard , this );
292+ Object base = field .unsafeReceiverCast ( receiver );
293+ return UnsafeAccess .unsafeGetLong (base , field . offset (), guard , this );
288294 }
289295 }
290- return getLongUnexpected (store , expectedShape , guard );
296+ return getLongUnexpected (receiver , expectedShape , guard );
291297 }
292298
293299 /**
@@ -303,18 +309,19 @@ private long getLongUnexpected(DynamicObject store, Shape expectedShape, boolean
303309 * @see #getInternal(DynamicObject, Shape, boolean)
304310 */
305311 final double getDoubleInternal (DynamicObject store , Shape expectedShape , boolean guard ) throws UnexpectedResultException {
312+ DynamicObject receiver = unsafeNonNullCast (store );
306313 if (isDoubleLocation ()) {
307314 if (field == null ) {
308- Object array = getPrimitiveArray (store , guard );
315+ Object array = getPrimitiveArray (receiver , guard );
309316 long offset = getPrimitiveArrayOffset ();
310317 return UnsafeAccess .unsafeGetDouble (array , offset , guard , this );
311318 } else {
312- field .receiverCheck ( store );
313- long longValue = UnsafeAccess .unsafeGetLong (store , getFieldOffset (), guard , this );
319+ Object base = field .unsafeReceiverCast ( receiver );
320+ long longValue = UnsafeAccess .unsafeGetLong (base , field . offset (), guard , this );
314321 return Double .longBitsToDouble (longValue );
315322 }
316323 }
317- return getDoubleUnexpected (store , expectedShape , guard );
324+ return getDoubleUnexpected (receiver , expectedShape , guard );
318325 }
319326
320327 /**
@@ -436,16 +443,19 @@ final void setDoubleSafe(DynamicObject store, double value, boolean guard, boole
436443 * Stores a value in this location. Grows the object if necessary. It is the caller's
437444 * responsibility to check that the value is compatible with this location first.
438445 *
439- * @param receiver storage object
446+ * @param store storage object
440447 * @param value the value to be stored
441448 * @param guard the result of the shape check guarding this property write or {@code false}
442449 * @param oldShape the expected shape before the set
443450 * @param newShape the expected shape after the set
444451 * @see #canStoreValue(Object).
445452 */
446- final void setInternal (DynamicObject receiver , Object value , boolean guard , Shape oldShape , Shape newShape ) {
453+ @ SuppressWarnings ("hiding" )
454+ final void setInternal (DynamicObject store , Object value , boolean guard , Shape oldShape , Shape newShape ) {
447455 assert canStoreValue (value ) : value ;
456+ DynamicObject receiver = unsafeNonNullCast (store );
448457 long idx = Integer .toUnsignedLong (index );
458+ FieldInfo field = this .field ;
449459 boolean init = newShape != oldShape ;
450460 if (init ) {
451461 DynamicObjectSupport .grow (receiver , oldShape , newShape );
@@ -467,9 +477,8 @@ final void setInternal(DynamicObject receiver, Object value, boolean guard, Shap
467477 offset = computeObjectArrayOffset (idx );
468478 UnsafeAccess .unsafePutObject (base , offset , value , this );
469479 } else {
470- field .receiverCheck (receiver );
471- base = receiver ;
472- offset = getFieldOffset ();
480+ base = field .unsafeReceiverCast (receiver );
481+ offset = field .offset ();
473482 UnsafeAccess .unsafePutObject (base , offset , value , this );
474483 }
475484 } else { // primitive location
@@ -519,9 +528,9 @@ final void setInternal(DynamicObject receiver, Object value, boolean guard, Shap
519528 assert isConstantLocation () : this ;
520529 return ;
521530 }
522- field .receiverCheck (receiver );
523- long offset = getFieldOffset ();
524- UnsafeAccess .unsafePutLong (receiver , offset , longValue , this );
531+ Object base = field .unsafeReceiverCast (receiver );
532+ long offset = field . offset ();
533+ UnsafeAccess .unsafePutLong (base , offset , longValue , this );
525534 }
526535 }
527536
@@ -773,6 +782,20 @@ static Object getPrimitiveArray(DynamicObject store, boolean condition) {
773782 return UnsafeAccess .hostUnsafeCast (store .getPrimitiveStore (), int [].class , condition , true , true );
774783 }
775784
785+ private static DynamicObject unsafeNonNullCast (DynamicObject receiver ) {
786+ /*
787+ * The shape check already performs an implicit null check, so the receiver is guaranteed to
788+ * be non-null here, but when compiling methods separately we might not know this yet.
789+ * Hence, we use an unsafe cast in the interpreter to avoid compiling any null code paths.
790+ * In PE OTOH, the redundant ValueAnchor+Pi would just mean extra work for the compiler.
791+ */
792+ if (CompilerDirectives .inInterpreter () && !ObjectStorageOptions .ReceiverCheck && ImageInfo .inImageCode ()) {
793+ return UnsafeAccess .hostUnsafeCast (receiver , DynamicObject .class , false , true , false );
794+ } else {
795+ return receiver ;
796+ }
797+ }
798+
776799 static RuntimeException incompatibleLocationException () {
777800 CompilerDirectives .transferToInterpreterAndInvalidate ();
778801 throw UncheckedIncompatibleLocationException .instance ();
0 commit comments