Skip to content

Commit 112b1d0

Browse files
woessbulasevich
authored andcommitted
Block future property assumptions on indirect shape transitions.
(cherry picked from commit ed5aa9af4dc77f49a56755789c7920ce84ff5deb)
1 parent 4e39f63 commit 112b1d0

File tree

2 files changed

+40
-22
lines changed

2 files changed

+40
-22
lines changed

truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutStrategy.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ private Location createLocationForValue(ShapeImpl oldShape, Object value, long p
160160

161161
protected ShapeImpl definePropertyChangeFlags(ShapeImpl oldShape, Property existing, Object value, int propertyFlags, long putFlags) {
162162
assert existing.getFlags() != propertyFlags;
163-
oldShape.onPropertyTransition(existing);
164163
if (existing.getLocation().canStore(value)) {
165164
Property newProperty = Property.create(existing.getKey(), existing.getLocation(), propertyFlags);
166165
return replaceProperty(oldShape, existing, newProperty);
@@ -170,7 +169,6 @@ protected ShapeImpl definePropertyChangeFlags(ShapeImpl oldShape, Property exist
170169
}
171170

172171
protected ShapeImpl definePropertyGeneralize(ShapeImpl oldShape, Property oldProperty, Object value, com.oracle.truffle.api.object.LocationFactory locationFactory, long putFlags) {
173-
oldShape.onPropertyTransition(oldProperty);
174172
if (Flags.isSeparateShape(putFlags)) {
175173
Location newLocation = createLocationForValue(oldShape, value, putFlags, locationFactory);
176174
Property newProperty = ((PropertyImpl) oldProperty).relocate(newLocation);
@@ -189,7 +187,6 @@ protected ShapeImpl generalizeProperty(Property oldProperty, Object value, Shape
189187
Location oldLocation = oldProperty.getLocation();
190188
Location newLocation = currentShape.allocator().locationForValueUpcast(value, oldLocation, putFlags);
191189
Property newProperty = ((PropertyImpl) oldProperty).relocate(newLocation);
192-
nextShape.onPropertyTransition(oldProperty);
193190
return replaceProperty(nextShape, oldProperty, newProperty);
194191
}
195192

@@ -226,10 +223,9 @@ protected ShapeImpl replaceProperty(ShapeImpl shape, Property oldProperty, Prope
226223

227224
/** @since 0.17 or earlier */
228225
protected ShapeImpl removeProperty(ShapeImpl shape, Property property) {
229-
shape.onPropertyTransition(property);
230-
231226
boolean direct = shape.isShared();
232227
RemovePropertyTransition transition = newRemovePropertyTransition(property, direct);
228+
shape.onPropertyTransition(transition);
233229
ShapeImpl cachedShape = shape.queryTransition(transition);
234230
if (cachedShape != null) {
235231
return ensureValid(cachedShape);
@@ -306,9 +302,8 @@ private static ShapeImpl directReplacePropertyInner(ShapeImpl shape, Property ol
306302
return shape;
307303
}
308304

309-
shape.onPropertyTransition(oldProperty);
310-
311-
Transition replacePropertyTransition = new Transition.DirectReplacePropertyTransition(oldProperty, newProperty);
305+
var replacePropertyTransition = new Transition.DirectReplacePropertyTransition(oldProperty, newProperty);
306+
shape.onPropertyTransition(replacePropertyTransition);
312307
ShapeImpl cachedShape = shape.queryTransition(replacePropertyTransition);
313308
if (cachedShape != null) {
314309
return cachedShape;
@@ -326,6 +321,7 @@ private static ShapeImpl directReplacePropertyInner(ShapeImpl shape, Property ol
326321
}
327322

328323
protected ShapeImpl separateReplaceProperty(ShapeImpl shape, Property oldProperty, Property newProperty) {
324+
shape.invalidateAllPropertyAssumptions();
329325
ShapeImpl newRoot = shape.createShape(shape.getLayout(), shape.sharedData, null, shape.objectType, PropertyMap.empty(), null, shape.getLayout().createAllocator(), shape.flags);
330326
ShapeImpl newShape = newRoot;
331327
boolean found = false;
@@ -343,6 +339,7 @@ protected ShapeImpl separateReplaceProperty(ShapeImpl shape, Property oldPropert
343339
}
344340

345341
protected ShapeImpl createSeparateShape(ShapeImpl shape) {
342+
shape.invalidateAllPropertyAssumptions();
346343
ShapeImpl newRoot = shape.createShape(shape.getLayout(), shape.sharedData, null, shape.objectType, PropertyMap.empty(), null, shape.getLayout().createAllocator(), shape.flags);
347344
ShapeImpl newShape = newRoot;
348345
for (Iterator<Property> iterator = shape.getPropertyMap().orderedValueIterator(); iterator.hasNext();) {
@@ -371,9 +368,9 @@ protected ShapeImpl addProperty(ShapeImpl shape, Property property, boolean ensu
371368

372369
private ShapeImpl addPropertyInner(ShapeImpl shape, Property property) {
373370
assert !(shape.hasProperty(property.getKey())) : "duplicate property " + property.getKey();
374-
shape.onPropertyTransition(property);
375371

376372
AddPropertyTransition addTransition = newAddPropertyTransition(property);
373+
shape.onPropertyTransition(addTransition);
377374
ShapeImpl cachedShape = shape.queryTransition(addTransition);
378375
if (cachedShape != null) {
379376
return cachedShape;

truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -571,17 +571,18 @@ public ShapeImpl addProperty(Property property) {
571571
}
572572

573573
/** @since 0.17 or earlier */
574-
@TruffleBoundary
575-
protected void onPropertyTransition(Property property) {
576-
onPropertyTransitionWithKey(property.getKey());
574+
protected final void onPropertyTransition(Transition.PropertyTransition propertyTransition) {
575+
if (allowPropertyAssumptions()) {
576+
invalidatePropertyAssumption(propertyTransition.getPropertyKey(), propertyTransition.isDirect());
577+
}
577578
}
578579

579-
final void onPropertyTransitionWithKey(Object propertyKey) {
580-
if (allowPropertyAssumptions()) {
581-
PropertyAssumptions propertyAssumptions = getPropertyAssumptions();
582-
if (propertyAssumptions != null) {
583-
propertyAssumptions.invalidatePropertyAssumption(propertyKey);
584-
}
580+
private void invalidatePropertyAssumption(Object propertyKey, boolean onlyExisting) {
581+
PropertyAssumptions propertyAssumptions = onlyExisting
582+
? getPropertyAssumptions()
583+
: getOrCreatePropertyAssumptions();
584+
if (propertyAssumptions != null) {
585+
propertyAssumptions.invalidatePropertyAssumption(propertyKey, onlyExisting);
585586
}
586587
}
587588

@@ -1144,7 +1145,8 @@ protected static int checkObjectFlags(int flags) {
11441145
@TruffleBoundary
11451146
@Override
11461147
public Assumption getPropertyAssumption(Object key) {
1147-
if (allowPropertyAssumptions()) {
1148+
// Deny new property assumptions from being made if shape is already obsolete.
1149+
if (allowPropertyAssumptions() && this.isValid()) {
11481150
Assumption propertyAssumption = getOrCreatePropertyAssumptions().getPropertyAssumption(key);
11491151
if (propertyAssumption != null && propertyAssumption.isValid()) {
11501152
return propertyAssumption;
@@ -1366,14 +1368,32 @@ synchronized Assumption getPropertyAssumption(Object propertyName) {
13661368
return assumption;
13671369
}
13681370

1369-
synchronized void invalidatePropertyAssumption(Object propertyName) {
1371+
synchronized void invalidatePropertyAssumption(Object propertyName, boolean onlyExisting) {
13701372
CompilerAsserts.neverPartOfCompilation();
13711373
EconomicMap<Object, Assumption> map = stablePropertyAssumptions;
13721374
Assumption assumption = map.get(propertyName);
1373-
if (assumption != null && assumption != Assumption.NEVER_VALID) {
1375+
if (assumption == Assumption.NEVER_VALID) {
1376+
return;
1377+
}
1378+
if (assumption != null) {
13741379
assumption.invalidate("invalidatePropertyAssumption");
1380+
}
1381+
/*
1382+
* Direct property transitions can happen only once per object as they always lead to
1383+
* new shapes, so we only need to invalidate already registered assumptions.
1384+
*
1385+
* Indirect property transitions, OTOH, can form transition cycles in the shape tree
1386+
* that may cause toggling between existing shapes for the same object, and since
1387+
* already cached shape transitions fly under the radar of future property assumptions,
1388+
* we have to block any future assumptions from being registered for this property.
1389+
*/
1390+
if (assumption != null || !onlyExisting) {
13751391
map.put(propertyName, Assumption.NEVER_VALID);
1376-
propertyAssumptionsRemoved.inc();
1392+
if (assumption != null) {
1393+
propertyAssumptionsRemoved.inc();
1394+
} else {
1395+
propertyAssumptionsBlocked.inc();
1396+
}
13771397
}
13781398
}
13791399

@@ -1398,5 +1418,6 @@ Assumption getSingleContextAssumption() {
13981418
static final DebugCounter shapeCacheWeakKeys = DebugCounter.create("Shape cache weak keys");
13991419
static final DebugCounter propertyAssumptionsCreated = DebugCounter.create("Property assumptions created");
14001420
static final DebugCounter propertyAssumptionsRemoved = DebugCounter.create("Property assumptions removed");
1421+
static final DebugCounter propertyAssumptionsBlocked = DebugCounter.create("Property assumptions blocked");
14011422

14021423
}

0 commit comments

Comments
 (0)