@@ -390,14 +390,13 @@ static RemovePlan prepareRemove(Shape shapeBefore, Shape shapeAfter, Property re
390390 moves .add (move );
391391 }
392392 }
393+ Location removedPropertyLoc = removedProperty .getLocation ();
394+ if (!removedPropertyLoc .isValue ()) {
395+ // Use a no-op move to clear the location of the removed property. Must be first.
396+ moves .add (new Move (removedPropertyLoc , null , removedPropertyLoc .getOrdinal (), Integer .MIN_VALUE ));
397+ }
393398 if (canMoveInPlace ) {
394- if (moves .isEmpty ()) {
395- Location removedPropertyLoc = removedProperty .getLocation ();
396- if (!removedPropertyLoc .isPrimitive ()) {
397- // Use a no-op move to clear the location of the removed property.
398- moves .add (new Move (removedPropertyLoc , removedPropertyLoc , 0 , 0 ));
399- }
400- } else if (!isSorted (moves )) {
399+ if (!isSorted (moves )) {
401400 moves .sort (Move ::compareTo );
402401 }
403402 }
@@ -415,6 +414,10 @@ private static boolean isSorted(List<Move> moves) {
415414 return true ;
416415 }
417416
417+ /**
418+ * Moves the value from one location to another, and clears the from location. If both locations
419+ * are the same, only clears the location.
420+ */
418421 private static final class Move implements Comparable <Move > {
419422 private final Location fromLoc ;
420423 private final Location toLoc ;
@@ -424,30 +427,51 @@ private static final class Move implements Comparable<Move> {
424427 private static final Move [] EMPTY_ARRAY = new Move [0 ];
425428
426429 Move (Location fromLoc , Location toLoc , int fromOrd , int toOrd ) {
427- assert ( fromLoc == toLoc ) == ( fromOrd == toOrd ) ;
428- this .fromLoc = fromLoc ;
430+ assert fromLoc != toLoc ;
431+ this .fromLoc = Objects . requireNonNull ( fromLoc ) ;
429432 this .toLoc = toLoc ;
430433 this .fromOrd = fromOrd ;
431434 this .toOrd = toOrd ;
432435 }
433436
434437 void perform (DynamicObject obj ) {
435- if (fromLoc == toLoc ) {
436- return ;
438+ if (toLoc != null ) {
439+ performSet ( obj , performGet ( obj )) ;
437440 }
438- performSet (obj , performGet (obj ));
441+ /*
442+ * It does not matter for correctness whether we clear after the get or set. Clearing
443+ * after the set might be slightly preferable w.r.t. store ordering.
444+ */
445+ clear (obj );
439446 }
440447
441448 Object performGet (DynamicObject obj ) {
442449 return fromLoc .get (obj , false );
443450 }
444451
445452 void performSet (DynamicObject obj , Object value ) {
453+ if (toLoc == null ) {
454+ return ; // clear only
455+ }
446456 toLoc .setSafe (obj , value , false , true );
447457 }
448458
449- void clear (DynamicObject obj ) {
450- // clear location to avoid memory leak
459+ Object performGetAndClear (DynamicObject obj ) {
460+ Object value = performGet (obj );
461+ clear (obj );
462+ return value ;
463+ }
464+
465+ /*
466+ * Clears the location to avoid potential memory leaks AND kills the from location identity.
467+ *
468+ * Note: It is important that we always set the "from" location in compiled code to kill the
469+ * location identity at this point, so as to prevent reads from that location identity (of
470+ * the old shape) to move below any write to the same memory location but with a different
471+ * location identity (of the new shape), since that would be seen as independent and
472+ * therefore not kill the "from" location that is being overwritten or cleared. (GR-59981)
473+ */
474+ private void clear (DynamicObject obj ) {
451475 fromLoc .clear (obj );
452476 }
453477
@@ -498,25 +522,19 @@ void perform(DynamicObject object) {
498522 moves [i ].perform (object );
499523 }
500524
501- if (moves .length > 0 ) {
502- moves [0 ].clear (object );
503- }
504-
505525 DynamicObjectSupport .trimToSize (object , shapeBefore , shapeAfter );
506- object .setShape (shapeAfter );
507526 } else {
508527 // we cannot perform the moves in place, so stash away the values
509528 Object [] tempValues = new Object [moves .length ];
510529 for (int i = moves .length - 1 ; i >= 0 ; i --) {
511- tempValues [i ] = moves [i ].performGet (object );
512- moves [i ].clear (object );
530+ tempValues [i ] = moves [i ].performGetAndClear (object );
513531 }
514532 DynamicObjectSupport .resize (object , shapeBefore , shapeAfter );
515533 for (int i = moves .length - 1 ; i >= 0 ; i --) {
516534 moves [i ].performSet (object , tempValues [i ]);
517535 }
518- object .setShape (shapeAfter );
519536 }
537+ object .setShape (shapeAfter );
520538 }
521539
522540 @ TruffleBoundary
0 commit comments