@@ -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
0 commit comments