Skip to content

Commit ddb6907

Browse files
committed
Always clear the source location when moving values between locations.
1 parent 397718f commit ddb6907

File tree

1 file changed

+40
-22
lines changed

1 file changed

+40
-22
lines changed

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

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)