diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index 7851eac0ecb2..e7a4042dcc8a 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -483,7 +483,9 @@ def _truffle_gate_runner(args, tasks): with Task('Truffle Signature Tests', tasks, tags=TruffleGateTags.sigtest) as t: if t: sigtest(['--check', 'binary']) with Task('Truffle UnitTests', tasks, tags=TruffleGateTags.truffle_test) as t: - if t: unittest(list(['--suite', 'truffle', '--enable-timing', '--verbose', '--max-class-failures=25'])) + if t: + unittest(['--suite', 'truffle', '--enable-timing', '--verbose', '--max-class-failures=25']) + unittest(['--suite', 'truffle', '--enable-timing', '-Dtruffle.object.LayoutFactory=com.oracle.truffle.api.object.CoreLayoutFactory', 'com.oracle.truffle.object']) if jdk.javaCompliance >= '22': with Task('Truffle NFI tests with Panama Backend', tasks, tags=TruffleGateTags.panama_test) as t: if t: diff --git a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/basic/test/DOTestAsserts.java b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/basic/test/DOTestAsserts.java index 746892ed741f..7edff5d8fd10 100644 --- a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/basic/test/DOTestAsserts.java +++ b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/basic/test/DOTestAsserts.java @@ -40,6 +40,9 @@ */ package com.oracle.truffle.object.basic.test; +import static org.hamcrest.CoreMatchers.either; +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -141,6 +144,14 @@ public static Class getLocationType(Location location) { } } + public static void assumeExtLayout() { + Shape shape = Shape.newBuilder().build(); + assertThat("Unexpected Shape class name (the assertion may need to be updated if the code is refactored)", + shape.getClass().getName(), either(endsWith("ShapeExt")).or(endsWith("ShapeBasic"))); + Assume.assumeTrue("Test is specific to the Extended Dynamic Object Layout", + shape.getClass().getName().endsWith("ShapeExt")); + } + public static Location assumeCoreLocation(Location location) { Assume.assumeTrue(isCoreLocation(location)); return location; diff --git a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR42603.java b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR42603.java index 506966ce5056..a6d092cc0de3 100644 --- a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR42603.java +++ b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR42603.java @@ -40,6 +40,8 @@ */ package com.oracle.truffle.object.ext.test; +import static com.oracle.truffle.object.basic.test.DOTestAsserts.assumeExtLayout; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; @@ -54,7 +56,6 @@ import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.object.ext.test.ObjectModelRegressionTest.TestDynamicObject; -import com.oracle.truffle.tck.tests.TruffleTestAssumptions; public class GR42603 { @@ -63,7 +64,7 @@ public class GR42603 { @Test public void testReplacePropertyRace() throws Throwable { - TruffleTestAssumptions.assumeEnterpriseRuntime(); + assumeExtLayout(); for (int i = 0; i < 100; i++) { testConcurrentReplaceProperty(); } diff --git a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR52036.java b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR52036.java index 296d81858078..3606b09a848d 100644 --- a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR52036.java +++ b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/GR52036.java @@ -40,6 +40,7 @@ */ package com.oracle.truffle.object.ext.test; +import static com.oracle.truffle.object.basic.test.DOTestAsserts.assumeExtLayout; import static com.oracle.truffle.object.basic.test.DOTestAsserts.getTypeAssumption; import static com.oracle.truffle.object.basic.test.DOTestAsserts.getTypeAssumptionRecord; import static org.junit.Assert.assertFalse; @@ -55,7 +56,6 @@ import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.object.Shape; -import com.oracle.truffle.tck.tests.TruffleTestAssumptions; public class GR52036 { @@ -70,7 +70,7 @@ public class GR52036 { @SuppressWarnings("try") @Test public void testGR52036Reproducer() throws Throwable { - TruffleTestAssumptions.assumeEnterpriseRuntime(); + assumeExtLayout(); class ObjType1 extends DynamicObject { protected ObjType1(Shape shape) { diff --git a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/ObjectModelRegressionTest.java b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/ObjectModelRegressionTest.java index 46d5db23cbff..f40efeb577ba 100644 --- a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/ObjectModelRegressionTest.java +++ b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/ObjectModelRegressionTest.java @@ -42,6 +42,7 @@ import static com.oracle.truffle.object.basic.test.DOTestAsserts.assertObjectLocation; import static com.oracle.truffle.object.basic.test.DOTestAsserts.assertPrimitiveLocation; +import static com.oracle.truffle.object.basic.test.DOTestAsserts.assumeExtLayout; import static com.oracle.truffle.object.basic.test.DOTestAsserts.invokeGetter; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -56,6 +57,8 @@ import java.util.List; import java.util.Map; +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -67,7 +70,6 @@ import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.test.AbstractParametrizedLibraryTest; -import com.oracle.truffle.tck.tests.TruffleTestAssumptions; @SuppressWarnings("deprecation") @RunWith(Parameterized.class) @@ -386,7 +388,7 @@ public void testChangeFlagsConstantToNonConstant() { @Test public void testTryMergeShapes() { - TruffleTestAssumptions.assumeEnterpriseRuntime(); + assumeExtLayout(); // Assume (MaxMergeDepth >= 5) Shape emptyShape = Shape.newBuilder().allowImplicitCastIntToDouble(true).build(); @@ -437,7 +439,7 @@ public void testTryMergeShapes() { @Test public void testTryMergeShapes2() { - TruffleTestAssumptions.assumeEnterpriseRuntime(); + assumeExtLayout(); // Assume (MaxMergeDepth >= 5 && MaxMergeDiff >= 2) @@ -473,6 +475,25 @@ public void testTryMergeShapes2() { assertSame(b.getShape(), a.getShape()); } + @Test + public void testBooleanLocationTypeAssumption() { + assumeExtLayout(); + + Shape emptyShape = Shape.newBuilder().build(); + + DynamicObject obj = new TestDynamicObject(emptyShape); + + DynamicObjectLibrary library = createLibrary(DynamicObjectLibrary.class, obj); + + library.put(obj, "b1", true); + library.put(obj, "b2", true); + library.put(obj, "b2", false); + + Shape shape = obj.getShape(); + MatcherAssert.assertThat(shape.getProperty("b1").getLocation().toString(), CoreMatchers.containsString("Boolean")); + MatcherAssert.assertThat(shape.getProperty("b2").getLocation().toString(), CoreMatchers.containsString("Boolean")); + } + /** * Tests that onPropertyTransition is called by replace and remove property transitions. */ @@ -510,6 +531,132 @@ public void testPropertyAssumptionInvalidation() { assertFalse(assumption.toString(), assumption.isValid()); } + /** + * Tests that property assumptions are blocked after remove property transitions. + */ + @Test + public void testPropertyAssumptionInvalidAfterRemove() { + Shape emptyShape = Shape.newBuilder().propertyAssumptions(true).build(); + + DynamicObject h1 = new TestDynamicObject(emptyShape); + DynamicObjectLibrary on = createLibrary(DynamicObjectLibrary.class, h1); + DynamicObjectLibrary off = createLibrary(DynamicObjectLibrary.class, h1); + + // initialize caches + on.put(h1, "name", h1); + on.put(h1, "alias", h1); + off.removeKey(h1, "name"); + off.removeKey(h1, "alias"); + + DynamicObject h2 = new TestDynamicObject(emptyShape); + // repeat on another object with cached transitions + on.put(h2, "name", h2); + on.put(h2, "alias", h2); + + Assumption aliasAssumption = h2.getShape().getPropertyAssumption("alias"); + assertFalse("Property assumption for 'alias' should already be invalid: " + aliasAssumption, aliasAssumption.isValid()); + + on.put(h2, "alias", h2); + off.removeKey(h2, "name"); + off.removeKey(h2, "alias"); + } + + /** + * Tests that property assumptions are blocked after replace property transitions. + */ + @Test + public void testPropertyAssumptionInvalidAfterReplace1() { + assumeExtLayout(); + + Shape emptyShape = Shape.newBuilder().propertyAssumptions(true).build(); + + int flag = 2; + DynamicObject h1 = new TestDynamicObject(emptyShape); + DynamicObjectLibrary on = createLibrary(DynamicObjectLibrary.class, h1); + DynamicObjectLibrary off = createLibrary(DynamicObjectLibrary.class, h1); + + // initialize caches + on.put(h1, "name", h1); + on.put(h1, "alias", h1); + off.setPropertyFlags(h1, "name", flag); + off.setPropertyFlags(h1, "alias", flag); + + DynamicObject h2 = new TestDynamicObject(emptyShape); + // repeat cached operations on another object + on.put(h2, "name", h2); + on.put(h2, "alias", h2); + + Assumption aliasAssumption = h2.getShape().getPropertyAssumption("alias"); + assertFalse("Property assumption for 'alias' should already be invalid: " + aliasAssumption, aliasAssumption.isValid()); + + on.put(h2, "alias", h2); + off.setPropertyFlags(h2, "name", flag); + off.setPropertyFlags(h2, "alias", flag); + + assertEquals(flag, h2.getShape().getProperty("name").getFlags()); + assertEquals(flag, h2.getShape().getProperty("alias").getFlags()); + } + + /** + * Tests that property assumptions are blocked after replace property transitions. + */ + @Test + public void testPropertyAssumptionInvalidAfterReplace2() { + assumeExtLayout(); + + Shape emptyShape = Shape.newBuilder().propertyAssumptions(true).build(); + + int flag = 2; + DynamicObject h1 = new TestDynamicObject(emptyShape); + DynamicObjectLibrary on = createLibrary(DynamicObjectLibrary.class, h1); + DynamicObjectLibrary off = createLibrary(DynamicObjectLibrary.class, h1); + + // initialize caches + on.put(h1, "name", h1); + on.put(h1, "alias", h1); + off.putWithFlags(h1, "name", h1, flag); + off.putWithFlags(h1, "alias", h1, flag); + + DynamicObject h2 = new TestDynamicObject(emptyShape); + // repeat cached operations on another object + on.put(h2, "name", h2); + on.put(h2, "alias", h2); + + Assumption aliasAssumption = h2.getShape().getPropertyAssumption("alias"); + assertFalse("Property assumption for 'alias' should already be invalid: " + aliasAssumption, aliasAssumption.isValid()); + + on.put(h2, "alias", h2); + off.putWithFlags(h2, "name", h2, flag); + off.putWithFlags(h2, "alias", h2, flag); + + assertEquals(flag, h2.getShape().getProperty("name").getFlags()); + assertEquals(flag, h2.getShape().getProperty("alias").getFlags()); + } + + /** + * Tests that property assumptions are invalid after value type transitions. + */ + @Test + public void testPropertyAssumptionInvalidAfterTypeTransition() { + Shape emptyShape = Shape.newBuilder().propertyAssumptions(true).build(); + + DynamicObject h1 = new TestDynamicObject(emptyShape); + DynamicObjectLibrary lib = createLibrary(DynamicObjectLibrary.class, h1); + + // initialize caches + lib.put(h1, "name", 42); + lib.put(h1, "alias", 43); + + Assumption aliasAssumption = h1.getShape().getPropertyAssumption("alias"); + + DynamicObject h2 = new TestDynamicObject(emptyShape); + // repeat cached operations on another object + lib.put(h2, "name", 42); + lib.put(h2, "alias", h1); + + assertFalse("Property assumption for 'alias' should be invalid: " + aliasAssumption, aliasAssumption.isValid()); + } + static class TestDynamicObject extends DynamicObject { protected TestDynamicObject(Shape shape) { super(shape); diff --git a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/PolymorphicPrimitivesTest.java b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/PolymorphicPrimitivesTest.java index 47b0680e2295..1dbaf646fd8b 100644 --- a/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/PolymorphicPrimitivesTest.java +++ b/truffle/src/com.oracle.truffle.api.object.test/src/com/oracle/truffle/object/ext/test/PolymorphicPrimitivesTest.java @@ -42,6 +42,7 @@ import static com.oracle.truffle.object.basic.test.DOTestAsserts.assertObjectLocation; import static com.oracle.truffle.object.basic.test.DOTestAsserts.assertPrimitiveLocation; +import static com.oracle.truffle.object.basic.test.DOTestAsserts.assumeExtLayout; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @@ -61,7 +62,6 @@ import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.test.AbstractParametrizedLibraryTest; import com.oracle.truffle.object.ext.test.ObjectModelRegressionTest.TestDynamicObject; -import com.oracle.truffle.tck.tests.TruffleTestAssumptions; @SuppressWarnings("deprecation") @RunWith(Parameterized.class) @@ -86,7 +86,7 @@ private static DynamicObject newInstance(Shape emptyShape) { @Before public void before() { - TruffleTestAssumptions.assumeEnterpriseRuntime(); + assumeExtLayout(); } @Test diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/CoreAllocator.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/CoreAllocator.java index 4c77ebd012c7..cabfa9376347 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/CoreAllocator.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/CoreAllocator.java @@ -87,45 +87,37 @@ public CoreLocation declaredLocation(Object value) { @Override protected Location moveLocation(Location oldLocation) { - if (oldLocation instanceof LongLocation) { - return newLongLocation(oldLocation.isFinal(), ((LongLocation) oldLocation).isImplicitCastIntToLong()); + if (oldLocation instanceof LongLocation longLocation) { + return newLongLocation(longLocation.isImplicitCastIntToLong()); } else if (oldLocation instanceof IntLocation) { - return newIntLocation(oldLocation.isFinal()); - } else if (oldLocation instanceof DoubleLocation) { - return newDoubleLocation(oldLocation.isFinal(), ((DoubleLocation) oldLocation).isImplicitCastIntToDouble()); + return newIntLocation(); + } else if (oldLocation instanceof DoubleLocation doubleLocation) { + return newDoubleLocation(doubleLocation.isImplicitCastIntToDouble()); } else if (oldLocation instanceof BooleanLocation) { - return newBooleanLocation(oldLocation.isFinal()); + return newBooleanLocation(); } else if (oldLocation instanceof ObjectLocation) { - return newObjectLocation(oldLocation.isFinal(), ((ObjectLocation) oldLocation).isNonNull()); + return newObjectLocation(); } else { assert oldLocation instanceof CoreLocations.ValueLocation : oldLocation; return advance(oldLocation); } } - @Override - public Location newObjectLocation(boolean useFinal, boolean nonNull) { + private Location newObjectLocation() { if (ObjectStorageOptions.InObjectFields) { int insertPos = objectFieldSize; if (insertPos + OBJECT_SLOT_SIZE <= getLayout().getObjectFieldCount()) { return advance((Location) getLayout().getObjectFieldLocation(insertPos)); } } - return newObjectArrayLocation(useFinal, nonNull); + return newObjectArrayLocation(); } - @SuppressWarnings("unused") - private Location newObjectArrayLocation(boolean useFinal, boolean nonNull) { + private Location newObjectArrayLocation() { return advance(new ObjectArrayLocation(objectArraySize)); } - @Override - public Location newTypedObjectLocation(boolean useFinal, Class type, boolean nonNull) { - return newObjectLocation(useFinal, nonNull); - } - - @Override - protected Location newIntLocation(boolean useFinal) { + private Location newIntLocation() { if (ObjectStorageOptions.PrimitiveLocations && ObjectStorageOptions.IntegerLocations) { if (ObjectStorageOptions.InObjectFields && primitiveFieldSize + getLayout().getLongFieldSize() <= getLayout().getPrimitiveFieldCount()) { return advance(new IntLocationDecorator(getLayout().getPrimitiveFieldLocation(primitiveFieldSize))); @@ -134,15 +126,14 @@ protected Location newIntLocation(boolean useFinal) { return advance(new IntLocationDecorator(new LongArrayLocation(alignedIndex))); } } - return newObjectLocation(useFinal, true); + return newObjectLocation(); } - @Override - public Location newDoubleLocation(boolean useFinal) { - return newDoubleLocation(useFinal, getLayout().isAllowedIntToDouble()); + private Location newDoubleLocation() { + return newDoubleLocation(getLayout().isAllowedIntToDouble()); } - Location newDoubleLocation(boolean useFinal, boolean allowedIntToDouble) { + Location newDoubleLocation(boolean allowedIntToDouble) { if (ObjectStorageOptions.PrimitiveLocations && ObjectStorageOptions.DoubleLocations) { if (ObjectStorageOptions.InObjectFields && primitiveFieldSize + getLayout().getLongFieldSize() <= getLayout().getPrimitiveFieldCount()) { return advance(new DoubleLocationDecorator(getLayout().getPrimitiveFieldLocation(primitiveFieldSize), allowedIntToDouble)); @@ -151,15 +142,14 @@ Location newDoubleLocation(boolean useFinal, boolean allowedIntToDouble) { return advance(new DoubleLocationDecorator(new LongArrayLocation(alignedIndex), allowedIntToDouble)); } } - return newObjectLocation(useFinal, true); + return newObjectLocation(); } - @Override - public Location newLongLocation(boolean useFinal) { - return newLongLocation(useFinal, getLayout().isAllowedIntToLong()); + private Location newLongLocation() { + return newLongLocation(getLayout().isAllowedIntToLong()); } - Location newLongLocation(boolean useFinal, boolean allowedIntToLong) { + Location newLongLocation(boolean allowedIntToLong) { if (ObjectStorageOptions.PrimitiveLocations && ObjectStorageOptions.LongLocations) { if (ObjectStorageOptions.InObjectFields && primitiveFieldSize + getLayout().getLongFieldSize() <= getLayout().getPrimitiveFieldCount()) { return advance((Location) CoreLocations.createLongLocation(getLayout().getPrimitiveFieldLocation(primitiveFieldSize), allowedIntToLong)); @@ -168,59 +158,53 @@ Location newLongLocation(boolean useFinal, boolean allowedIntToLong) { return advance(new LongArrayLocation(alignedIndex, allowedIntToLong)); } } - return newObjectLocation(useFinal, true); + return newObjectLocation(); } - @Override - public Location newBooleanLocation(boolean useFinal) { + private Location newBooleanLocation() { if (ObjectStorageOptions.PrimitiveLocations && ObjectStorageOptions.BooleanLocations) { if (primitiveFieldSize + getLayout().getLongFieldSize() <= getLayout().getPrimitiveFieldCount()) { return advance(new BooleanLocationDecorator(getLayout().getPrimitiveFieldLocation(primitiveFieldSize))); } } - return newObjectLocation(useFinal, true); + return newObjectLocation(); } @Override - protected Location locationForValue(Object value, boolean useFinal, boolean nonNull) { - return locationForValue(value, useFinal, nonNull, 0); + public Location locationForValue(Object value) { + return locationForValue(value, 0); } - Location locationForValue(Object value, boolean useFinal, boolean nonNull, int putFlags) { + Location locationForValue(Object value, int putFlags) { if (Flags.isConstant(putFlags)) { return constantLocation(value); } else if (Flags.isDeclaration(putFlags)) { return declaredLocation(value); } if (value instanceof Integer) { - return newIntLocation(useFinal); + return newIntLocation(); } else if (value instanceof Double) { - return newDoubleLocation(useFinal, Flags.isImplicitCastIntToDouble(putFlags) || layout.isAllowedIntToDouble()); + return newDoubleLocation(Flags.isImplicitCastIntToDouble(putFlags) || layout.isAllowedIntToDouble()); } else if (value instanceof Long) { - return newLongLocation(useFinal, Flags.isImplicitCastIntToLong(putFlags) || layout.isAllowedIntToLong()); + return newLongLocation(Flags.isImplicitCastIntToLong(putFlags) || layout.isAllowedIntToLong()); } else if (value instanceof Boolean) { - return newBooleanLocation(useFinal); - } else if (ObjectStorageOptions.TypedObjectLocations && value != null) { - return newTypedObjectLocation(useFinal, value.getClass(), nonNull); + return newBooleanLocation(); } - return newObjectLocation(useFinal, nonNull && value != null); + return newObjectLocation(); } @Override - protected Location locationForType(Class type, boolean useFinal, boolean nonNull) { + public Location locationForType(Class type) { if (type == int.class) { - return newIntLocation(useFinal); + return newIntLocation(); } else if (type == double.class) { - return newDoubleLocation(useFinal); + return newDoubleLocation(); } else if (type == long.class) { - return newLongLocation(useFinal); + return newLongLocation(); } else if (type == boolean.class) { - return newBooleanLocation(useFinal); - } else if (ObjectStorageOptions.TypedObjectLocations && type != null && type != Object.class) { - assert !type.isPrimitive() : "unsupported primitive type"; - return newTypedObjectLocation(useFinal, type, nonNull); + return newBooleanLocation(); } - return newObjectLocation(useFinal, nonNull); + return newObjectLocation(); } @Override @@ -230,7 +214,7 @@ protected Location locationForValueUpcast(Object value, Location oldLocation, in if (oldLocation instanceof ConstantLocation && Flags.isConstant(putFlags)) { return constantLocation(value); } else if (oldLocation instanceof ValueLocation) { - return locationForValue(value, false, value != null); + return locationForValue(value, putFlags); } else if (oldLocation instanceof TypedLocation && ((TypedLocation) oldLocation).getType().isPrimitive()) { if (!shared && ((TypedLocation) oldLocation).getType() == int.class) { LongLocation primLocation = ((PrimitiveLocationDecorator) oldLocation).getInternalLongLocation(); @@ -242,9 +226,9 @@ protected Location locationForValueUpcast(Object value, Location oldLocation, in return new DoubleLocationDecorator(primLocation, true); } } - return newObjectLocation(oldLocation.isFinal(), value != null); + return newObjectLocation(); } - return locationForValue(value, false, value != null); + return locationForValue(value, putFlags); } /** diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/DefaultStrategy.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/DefaultStrategy.java index 556b2196533b..0d1de5272834 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/DefaultStrategy.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/DefaultStrategy.java @@ -88,7 +88,7 @@ public BaseAllocator createAllocator(LayoutImpl layout) { @Override protected Location createLocationForValue(ShapeImpl shape, Object value, int putFlags) { - return ((CoreAllocator) shape.allocator()).locationForValue(value, true, value != null, putFlags); + return ((CoreAllocator) shape.allocator()).locationForValue(value, putFlags); } @Override diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtAllocator.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtAllocator.java index be0b233ecb2e..bea855e77bd7 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtAllocator.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtAllocator.java @@ -46,7 +46,6 @@ import static com.oracle.truffle.api.object.ExtLayout.IntegerLocations; import static com.oracle.truffle.api.object.ExtLayout.LongLocations; import static com.oracle.truffle.api.object.ExtLayout.PrimitiveLocations; -import static com.oracle.truffle.api.object.ExtLayout.TypedObjectLocations; import static com.oracle.truffle.api.object.ExtLocations.DOUBLE_ARRAY_SLOT_SIZE; import static com.oracle.truffle.api.object.ExtLocations.INT_ARRAY_SLOT_SIZE; import static com.oracle.truffle.api.object.ExtLocations.LONG_ARRAY_SLOT_SIZE; @@ -70,7 +69,6 @@ import com.oracle.truffle.api.object.ExtLocations.LongArrayLocation; import com.oracle.truffle.api.object.ExtLocations.LongFieldLocation; import com.oracle.truffle.api.object.ExtLocations.LongLocation; -import com.oracle.truffle.api.object.ExtLocations.ObjectLocation; import com.oracle.truffle.api.object.ExtLocations.TypeAssumption; import com.oracle.truffle.api.object.ShapeImpl.BaseAllocator; @@ -107,13 +105,13 @@ public ExtLocation declaredLocation(Object value) { protected Location moveLocation(Location oldLocation) { final boolean decorateFinal = false; if (oldLocation instanceof IntLocation) { - return newIntLocation(decorateFinal, oldLocation); + return newIntLocation(decorateFinal, oldLocation, NO_VALUE); } else if (oldLocation instanceof DoubleLocation) { - return newDoubleLocation(decorateFinal, ((DoubleLocation) oldLocation).isImplicitCastIntToDouble(), oldLocation); + return newDoubleLocation(decorateFinal, ((DoubleLocation) oldLocation).isImplicitCastIntToDouble(), oldLocation, NO_VALUE); } else if (oldLocation instanceof LongLocation) { - return newLongLocation(decorateFinal, ((LongLocation) oldLocation).isImplicitCastIntToLong(), oldLocation); + return newLongLocation(decorateFinal, ((LongLocation) oldLocation).isImplicitCastIntToLong(), oldLocation, NO_VALUE); } else if (oldLocation instanceof BooleanLocation) { - return newBooleanLocation(decorateFinal, oldLocation); + return newBooleanLocation(decorateFinal, oldLocation, NO_VALUE); } else if (oldLocation instanceof AbstractObjectFieldLocation) { return newObjectLocation(decorateFinal, oldLocation, NO_VALUE); } else if (oldLocation instanceof AbstractObjectArrayLocation) { @@ -123,8 +121,7 @@ protected Location moveLocation(Location oldLocation) { return advance(oldLocation); } - @Override - public Location newObjectLocation(boolean useFinal, boolean nonNull) { + public Location newObjectLocation() { return newObjectLocation(false, null, NO_VALUE); } @@ -151,28 +148,19 @@ private Location newObjectArrayLocation(boolean decorateFinal, Location oldLocat return advance(location); } - @Override - public Location newTypedObjectLocation(boolean useFinal, Class type, boolean nonNull) { - return newTypedObjectLocation(type, nonNull, false, null, NO_VALUE); - } - - Location newTypedObjectLocation(Class type, boolean nonNull, boolean decorateFinal, Location oldLocation, Object value) { - if (TypedObjectLocations) { - if (InObjectFields) { - ExtLayout l = getLayout(); - int insertPos = objectFieldSize; - if (insertPos + OBJECT_SLOT_SIZE <= l.getObjectFieldCount()) { - FieldInfo fieldInfo = l.getObjectField(insertPos); - TypeAssumption initialTypeAssumption = getTypeAssumptionForTypeOrValue(type, nonNull, oldLocation, value); - Assumption initialFinalAssumption = getFinalAssumption(oldLocation, decorateFinal); - LocationImpl location = newObjectFieldLocationWithAssumption(insertPos, fieldInfo, initialTypeAssumption, initialFinalAssumption); - return advance(location); - } + private Location newTypedObjectLocation(Class type, boolean nonNull, boolean decorateFinal, Location oldLocation, Object value) { + if (InObjectFields) { + ExtLayout l = getLayout(); + int insertPos = objectFieldSize; + if (insertPos + OBJECT_SLOT_SIZE <= l.getObjectFieldCount()) { + FieldInfo fieldInfo = l.getObjectField(insertPos); + TypeAssumption initialTypeAssumption = getTypeAssumptionForTypeOrValue(type, nonNull, oldLocation, value); + Assumption initialFinalAssumption = getFinalAssumption(oldLocation, decorateFinal); + LocationImpl location = newObjectFieldLocationWithAssumption(insertPos, fieldInfo, initialTypeAssumption, initialFinalAssumption); + return advance(location); } - return newTypedObjectArrayLocation(type, nonNull, decorateFinal, oldLocation, value); - } else { - return newObjectLocation(decorateFinal, oldLocation, value); } + return newTypedObjectArrayLocation(type, nonNull, decorateFinal, oldLocation, value); } private Location newTypedObjectArrayLocation(Class type, boolean nonNull, boolean decorateFinal, Location oldLocation, Object value) { @@ -245,27 +233,18 @@ private static int tryAllocatePrimitiveSlot(ExtLayout l, int startIndex, final i // no primitive fields in this layout that are wide enough return -1; } - next: for (int fieldIndex = startIndex; fieldIndex < l.getPrimitiveFieldCount(); fieldIndex++) { + for (int fieldIndex = startIndex; fieldIndex < l.getPrimitiveFieldCount(); fieldIndex++) { // ensure alignment final int align = desiredBytes - 1; - while ((l.getPrimitiveField(fieldIndex).offset() & align) != 0) { - continue next; - } - FieldInfo fieldInfo = l.getPrimitiveField(fieldIndex); + if ((fieldInfo.offset() & align) != 0) { + continue; + } - // if we do not have enough space in one field, try to span multiple consecutive fields int availableBytes = fieldInfo.getBytes(); - int lastFieldIndex = fieldIndex; - while (availableBytes < desiredBytes && - lastFieldIndex + 1 < l.getPrimitiveFieldCount() && - l.getPrimitiveField(lastFieldIndex + 1).offset() == l.getPrimitiveField(lastFieldIndex).offset() + l.getPrimitiveField(lastFieldIndex).getBytes()) { - availableBytes += l.getPrimitiveField(lastFieldIndex + 1).getBytes(); - lastFieldIndex++; - } if (availableBytes < desiredBytes) { // this field is not suitable for the desired number of bytes, try the next one - continue next; + continue; } return fieldIndex; @@ -273,12 +252,11 @@ private static int tryAllocatePrimitiveSlot(ExtLayout l, int startIndex, final i return -1; } - @Override - public Location newIntLocation(boolean useFinal) { - return newIntLocation(false, null); + private Location newIntLocation() { + return newIntLocation(false, null, NO_VALUE); } - private Location newIntLocation(boolean decorateFinal, Location oldLocation) { + private Location newIntLocation(boolean decorateFinal, Location oldLocation, Object value) { if (PrimitiveLocations && IntegerLocations) { ExtLayout l = getLayout(); if (InObjectFields) { @@ -297,15 +275,14 @@ private Location newIntLocation(boolean decorateFinal, Location oldLocation) { return advance(location); } } - return newObjectLocation(decorateFinal, null, NO_VALUE); + return newObjectLocation(decorateFinal, oldLocation, value); } - @Override - public Location newDoubleLocation(boolean useFinal) { - return newDoubleLocation(false, getLayout().isAllowedIntToDouble(), null); + private Location newDoubleLocation() { + return newDoubleLocation(false, getLayout().isAllowedIntToDouble(), null, NO_VALUE); } - private Location newDoubleLocation(boolean decorateFinal, boolean allowIntToDouble, Location oldLocation) { + private Location newDoubleLocation(boolean decorateFinal, boolean allowIntToDouble, Location oldLocation, Object value) { if (PrimitiveLocations && DoubleLocations) { ExtLayout l = getLayout(); if (InObjectFields) { @@ -325,7 +302,7 @@ private Location newDoubleLocation(boolean decorateFinal, boolean allowIntToDoub return advance(location); } } - return newObjectLocation(decorateFinal, null, NO_VALUE); + return newObjectLocation(decorateFinal, oldLocation, value); } /** @@ -346,12 +323,11 @@ private static int alignArrayIndex(int index, int slotSize) { } } - @Override - public Location newLongLocation(boolean useFinal) { - return newLongLocation(false, getLayout().isAllowedIntToLong(), null); + private Location newLongLocation() { + return newLongLocation(false, getLayout().isAllowedIntToLong(), null, NO_VALUE); } - private Location newLongLocation(boolean decorateFinal, boolean allowIntToLong, Location oldLocation) { + private Location newLongLocation(boolean decorateFinal, boolean allowIntToLong, Location oldLocation, Object value) { if (PrimitiveLocations && LongLocations) { ExtLayout l = getLayout(); if (InObjectFields) { @@ -371,15 +347,14 @@ private Location newLongLocation(boolean decorateFinal, boolean allowIntToLong, return advance(location); } } - return newObjectLocation(decorateFinal, null, NO_VALUE); + return newObjectLocation(decorateFinal, oldLocation, value); } - @Override - public Location newBooleanLocation(boolean useFinal) { - return newBooleanLocation(false, null); + private Location newBooleanLocation() { + return newBooleanLocation(false, null, NO_VALUE); } - private Location newBooleanLocation(boolean decorateFinal, Location oldLocation) { + private Location newBooleanLocation(boolean decorateFinal, Location oldLocation, Object value) { if (PrimitiveLocations && BooleanLocations && InObjectFields) { ExtLayout l = getLayout(); int fieldIndex = tryAllocatePrimitiveSlot(l, primitiveFieldSize, Integer.BYTES); @@ -392,12 +367,7 @@ private Location newBooleanLocation(boolean decorateFinal, Location oldLocation) } } } - return newObjectLocation(decorateFinal, null, NO_VALUE); - } - - @Override - protected Location locationForValueUpcast(Object value, Location oldLocation) { - return locationForValueUpcast(value, oldLocation, 0); + return newObjectLocation(decorateFinal, oldLocation, value); } @Override @@ -408,56 +378,34 @@ protected Location locationForValueUpcast(Object value, Location oldLocation, in return constantLocation(value); } - assert !oldLocation.isFinal(); + // Object-typed locations should be able to store all values and therefore not reach here. + assert !oldLocation.isFinal() && !(oldLocation instanceof AbstractObjectLocation) : oldLocation; final boolean decorateFinal = false; Location newLocation = null; - if (shared) { - // if shape is shared, transition to an untyped location directly - newLocation = oldLocation instanceof AbstractObjectArrayLocation - ? newObjectArrayLocation(decorateFinal, oldLocation, NO_VALUE) - : newObjectLocation(decorateFinal, oldLocation, NO_VALUE); - } else if (oldLocation instanceof IntLocation) { + // if shape is shared, transition to an untyped location directly + if (!shared && oldLocation instanceof IntLocation) { boolean allowedIntToDouble = getLayout().isAllowedIntToDouble() || Flags.isImplicitCastIntToDouble(putFlags); boolean allowedIntToLong = getLayout().isAllowedIntToLong() || Flags.isImplicitCastIntToLong(putFlags); if (value instanceof Double && allowedIntToDouble) { - newLocation = newDoubleLocation(decorateFinal, allowedIntToDouble, oldLocation); + newLocation = newDoubleLocation(decorateFinal, allowedIntToDouble, oldLocation, NO_VALUE); } else if (value instanceof Long && allowedIntToLong) { - newLocation = newLongLocation(decorateFinal, allowedIntToLong, oldLocation); + newLocation = newLongLocation(decorateFinal, allowedIntToLong, oldLocation, NO_VALUE); } } if (newLocation == null) { - boolean nonNull = value != null && (!(oldLocation instanceof ObjectLocation) || ((ObjectLocation) oldLocation).isNonNull()); - Class type = oldLocation instanceof ObjectLocation ? ((ObjectLocation) oldLocation).getType() : Object.class; - boolean isArrayLocation = oldLocation instanceof AbstractObjectArrayLocation; - if (type != Object.class && (value == null || type.isInstance(value))) { - newLocation = isArrayLocation - ? newTypedObjectArrayLocation(type, nonNull, decorateFinal, null, NO_VALUE) - : newTypedObjectLocation(type, nonNull, decorateFinal, null, NO_VALUE); - } else { - // try superclass - type = type != Object.class ? getCommonSuperclassForValue(type, value) : type; - if (type != Object.class) { - newLocation = isArrayLocation - ? newTypedObjectArrayLocation(type, nonNull, decorateFinal, null, NO_VALUE) - : newTypedObjectLocation(type, nonNull, decorateFinal, null, NO_VALUE); - } else { - newLocation = isArrayLocation - ? newObjectArrayLocation(decorateFinal, null, NO_VALUE) - : newObjectLocation(decorateFinal, null, NO_VALUE); - } - } + newLocation = newObjectLocation(decorateFinal, oldLocation, NO_VALUE); } return newLocation; } @Override - protected Location locationForValue(Object value, boolean useFinal, boolean nonNull) { - return locationForValue(value, nonNull, 0); + public Location locationForValue(Object value) { + return locationForValue(value, 0); } - protected Location locationForValue(Object value, boolean nonNull, int putFlags) { + protected Location locationForValue(Object value, int putFlags) { if (Flags.isConstant(putFlags)) { return constantLocation(value); } else if (Flags.isDeclaration(putFlags)) { @@ -465,34 +413,32 @@ protected Location locationForValue(Object value, boolean nonNull, int putFlags) } boolean decorateFinal = true; if (value instanceof Integer) { - return newIntLocation(decorateFinal, null); + return newIntLocation(decorateFinal, null, value); } else if (value instanceof Double) { - return newDoubleLocation(decorateFinal, getLayout().isAllowedIntToDouble(), null); + return newDoubleLocation(decorateFinal, getLayout().isAllowedIntToDouble(), null, value); } else if (value instanceof Long) { - return newLongLocation(decorateFinal, getLayout().isAllowedIntToLong(), null); + return newLongLocation(decorateFinal, getLayout().isAllowedIntToLong(), null, value); } else if (value instanceof Boolean) { - return newBooleanLocation(decorateFinal, null); - } else if (TypedObjectLocations && value != null && value.getClass() != null) { - return newTypedObjectLocation(value.getClass(), nonNull, decorateFinal, null, value); + return newBooleanLocation(decorateFinal, null, value); } return newObjectLocation(decorateFinal, null, value); } @Override - protected Location locationForType(Class type, boolean useFinal, boolean nonNull) { + public Location locationForType(Class type) { if (type == int.class) { - return newIntLocation(useFinal); + return newIntLocation(); } else if (type == double.class) { - return newDoubleLocation(useFinal); + return newDoubleLocation(); } else if (type == long.class) { - return newLongLocation(useFinal); + return newLongLocation(); } else if (type == boolean.class) { - return newBooleanLocation(useFinal); - } else if (ExtLayout.TypedObjectLocations && type != null && type != Object.class) { + return newBooleanLocation(); + } else if (type != null && type != Object.class) { assert !type.isPrimitive() : "unsupported primitive type"; - return newTypedObjectLocation(useFinal, type, nonNull); + return newTypedObjectLocation(type, false, false, null, NO_VALUE); } - return newObjectLocation(useFinal, nonNull); + return newObjectLocation(); } static Class getCommonSuperclass(Class a, Class b) { diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayout.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayout.java index 9e2be3558b89..62b0b8b2c6be 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayout.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayout.java @@ -65,7 +65,6 @@ final class ExtLayout extends LayoutImpl { public static final boolean DoubleLocations = booleanOption(OPTION_PREFIX + "DoubleLocations", true); public static final boolean LongLocations = booleanOption(OPTION_PREFIX + "LongLocations", true); public static final boolean BooleanLocations = booleanOption(OPTION_PREFIX + "BooleanLocations", true); - public static final boolean TypedObjectLocations = booleanOption(OPTION_PREFIX + "TypedObjectLocations", true); public static final boolean InObjectFields = booleanOption(OPTION_PREFIX + "InObjectFields", true); public static final boolean UseVarHandle = booleanOption(OPTION_PREFIX + "UseVarHandle", false); diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayoutStrategy.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayoutStrategy.java index d33916935fce..d6bed2f4334d 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayoutStrategy.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ExtLayoutStrategy.java @@ -77,7 +77,7 @@ public void visitObjectArray(int index, int count) { @Override protected Location createLocationForValue(ShapeImpl shape, Object value, int putFlags) { - return ((ExtAllocator) shape.allocator()).locationForValue(value, value != null, putFlags); + return ((ExtAllocator) shape.allocator()).locationForValue(value, putFlags); } @Override diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/LayoutStrategy.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/LayoutStrategy.java index 845313b18811..843a6a79a646 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/LayoutStrategy.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/LayoutStrategy.java @@ -138,7 +138,6 @@ protected Class detectLocationType(Object value) { protected ShapeImpl definePropertyChangeFlags(ShapeImpl oldShape, Property existing, Object value, int propertyFlags, int putFlags) { assert existing.getFlags() != propertyFlags; - oldShape.onPropertyTransition(existing); if (existing.getLocation().canStore(value)) { Property newProperty = Property.create(existing.getKey(), existing.getLocation(), propertyFlags); return replaceProperty(oldShape, existing, newProperty); @@ -148,7 +147,6 @@ protected ShapeImpl definePropertyChangeFlags(ShapeImpl oldShape, Property exist } protected ShapeImpl definePropertyGeneralize(ShapeImpl oldShape, Property oldProperty, Object value, int putFlags) { - oldShape.onPropertyTransition(oldProperty); if (Flags.isSeparateShape(putFlags)) { Location newLocation = createLocationForValue(oldShape, value, putFlags); Property newProperty = ((PropertyImpl) oldProperty).relocate(newLocation); @@ -167,7 +165,6 @@ protected ShapeImpl generalizeProperty(Property oldProperty, Object value, Shape Location oldLocation = oldProperty.getLocation(); Location newLocation = currentShape.allocator().locationForValueUpcast(value, oldLocation, putFlags); Property newProperty = ((PropertyImpl) oldProperty).relocate(newLocation); - nextShape.onPropertyTransition(oldProperty); return replaceProperty(nextShape, oldProperty, newProperty); } @@ -189,10 +186,9 @@ protected ShapeImpl replaceProperty(ShapeImpl shape, Property oldProperty, Prope } protected ShapeImpl removeProperty(ShapeImpl shape, Property property) { - shape.onPropertyTransition(property); - boolean direct = shape.isShared(); RemovePropertyTransition transition = newRemovePropertyTransition(property, direct); + shape.onPropertyTransition(transition); ShapeImpl cachedShape = shape.queryTransition(transition); if (cachedShape != null) { return ensureValid(cachedShape); @@ -269,9 +265,8 @@ private static ShapeImpl directReplacePropertyInner(ShapeImpl shape, Property ol return shape; } - shape.onPropertyTransition(oldProperty); - - Transition replacePropertyTransition = new Transition.DirectReplacePropertyTransition(oldProperty, newProperty); + var replacePropertyTransition = new Transition.DirectReplacePropertyTransition(oldProperty, newProperty); + shape.onPropertyTransition(replacePropertyTransition); ShapeImpl cachedShape = shape.queryTransition(replacePropertyTransition); if (cachedShape != null) { return cachedShape; @@ -289,6 +284,7 @@ private static ShapeImpl directReplacePropertyInner(ShapeImpl shape, Property ol } protected ShapeImpl separateReplaceProperty(ShapeImpl shape, Property oldProperty, Property newProperty) { + shape.invalidateAllPropertyAssumptions(); ShapeImpl newRoot = shape.createShape(shape.getLayout(), shape.sharedData, null, shape.objectType, PropertyMap.empty(), null, shape.getLayout().createAllocator(), shape.flags); ShapeImpl newShape = newRoot; boolean found = false; @@ -306,6 +302,7 @@ protected ShapeImpl separateReplaceProperty(ShapeImpl shape, Property oldPropert } protected ShapeImpl createSeparateShape(ShapeImpl shape) { + shape.invalidateAllPropertyAssumptions(); ShapeImpl newRoot = shape.createShape(shape.getLayout(), shape.sharedData, null, shape.objectType, PropertyMap.empty(), null, shape.getLayout().createAllocator(), shape.flags); ShapeImpl newShape = newRoot; for (Iterator iterator = shape.getPropertyMap().orderedValueIterator(); iterator.hasNext();) { @@ -332,9 +329,9 @@ protected ShapeImpl addProperty(ShapeImpl shape, Property property, boolean ensu private ShapeImpl addPropertyInner(ShapeImpl shape, Property property) { assert !(shape.hasProperty(property.getKey())) : "duplicate property " + property.getKey(); - shape.onPropertyTransition(property); AddPropertyTransition addTransition = newAddPropertyTransition(property); + shape.onPropertyTransition(addTransition); ShapeImpl cachedShape = shape.queryTransition(addTransition); if (cachedShape != null) { return cachedShape; diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObjectStorageOptions.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObjectStorageOptions.java index d6eb07881889..03c3fa66092a 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObjectStorageOptions.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObjectStorageOptions.java @@ -52,7 +52,6 @@ private ObjectStorageOptions() { static final boolean DoubleLocations = booleanOption(OPTION_PREFIX + "DoubleLocations", true); static final boolean LongLocations = booleanOption(OPTION_PREFIX + "LongLocations", true); static final boolean BooleanLocations = booleanOption(OPTION_PREFIX + "BooleanLocations", true); - static final boolean TypedObjectLocations = booleanOption(OPTION_PREFIX + "TypedObjectLocations", true); /** * Allocation of in-object fields. diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObsolescenceStrategy.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObsolescenceStrategy.java index 029e1bbcd598..1eb57c2a8176 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObsolescenceStrategy.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ObsolescenceStrategy.java @@ -162,7 +162,8 @@ private ShapeImpl indirectReplaceProperty(ShapeImpl shape, Property oldProperty, assert oldProperty.getKey().equals(newProperty.getKey()); Object key = newProperty.getKey(); - Transition replacePropertyTransition = new Transition.IndirectReplacePropertyTransition(oldProperty, newProperty); + var replacePropertyTransition = new Transition.IndirectReplacePropertyTransition(oldProperty, newProperty); + shape.onPropertyTransition(replacePropertyTransition); ShapeImpl cachedShape = shape.queryTransition(replacePropertyTransition); if (cachedShape != null) { return cachedShape; diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ShapeImpl.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ShapeImpl.java index 8353fd291ceb..05dd1ed7bd74 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ShapeImpl.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/ShapeImpl.java @@ -510,17 +510,18 @@ public ShapeImpl addProperty(Property property) { return getLayoutStrategy().addProperty(this, property); } - @TruffleBoundary - protected void onPropertyTransition(Property property) { - onPropertyTransitionWithKey(property.getKey()); + protected final void onPropertyTransition(Transition.PropertyTransition propertyTransition) { + if (allowPropertyAssumptions()) { + invalidatePropertyAssumption(propertyTransition.getPropertyKey(), propertyTransition.isDirect()); + } } - final void onPropertyTransitionWithKey(Object propertyKey) { - if (allowPropertyAssumptions()) { - PropertyAssumptions propertyAssumptions = getPropertyAssumptions(); - if (propertyAssumptions != null) { - propertyAssumptions.invalidatePropertyAssumption(propertyKey); - } + private void invalidatePropertyAssumption(Object propertyKey, boolean onlyExisting) { + PropertyAssumptions propertyAssumptions = onlyExisting + ? getPropertyAssumptions() + : getOrCreatePropertyAssumptions(); + if (propertyAssumptions != null) { + propertyAssumptions.invalidatePropertyAssumption(propertyKey, onlyExisting); } } @@ -1023,7 +1024,8 @@ protected static int checkObjectFlags(int flags) { @TruffleBoundary @Override public Assumption getPropertyAssumption(Object key) { - if (allowPropertyAssumptions()) { + // Deny new property assumptions from being made if shape is already obsolete. + if (allowPropertyAssumptions() && this.isValid()) { Assumption propertyAssumption = getOrCreatePropertyAssumptions().getPropertyAssumption(key); if (propertyAssumption != null && propertyAssumption.isValid()) { return propertyAssumption; @@ -1082,18 +1084,6 @@ protected BaseAllocator(ShapeImpl shape) { protected abstract Location moveLocation(Location oldLocation); - protected abstract Location newObjectLocation(boolean useFinal, boolean nonNull); - - protected abstract Location newTypedObjectLocation(boolean useFinal, Class type, boolean nonNull); - - protected abstract Location newIntLocation(boolean useFinal); - - protected abstract Location newDoubleLocation(boolean useFinal); - - protected abstract Location newLongLocation(boolean useFinal); - - protected abstract Location newBooleanLocation(boolean useFinal); - /** * Creates a new location from a constant value. The value is stored in the shape rather * than in the object. @@ -1107,6 +1097,8 @@ public Location constantLocation(Object value) { /** * Creates a new declared location with a default value. A declared location only assumes a * type after the first set (initialization). + *

+ * Used by tests. * * @param value the default value */ @@ -1115,46 +1107,22 @@ public Location declaredLocation(Object value) { } /** - * Create a new location compatible with the given initial value. - * - * @param value the initial value this location is going to be assigned - * @param useFinal final location - * @param nonNull non-null location - */ - protected Location locationForValue(Object value, boolean useFinal, boolean nonNull) { - throw new UnsupportedOperationException(); - } - - /** + * Creates a new location compatible with the given initial value. + *

* Used by tests. */ - public Location locationForValue(Object value) { - return locationForValue(value, false, value != null); - } - - protected Location locationForValueUpcast(Object value, Location oldLocation) { - return locationForValueUpcast(value, oldLocation, 0); - } + public abstract Location locationForValue(Object value); protected abstract Location locationForValueUpcast(Object value, Location oldLocation, int putFlags); /** - * Create a new location for a fixed type. It can only be assigned to values of this type. + * Creates a new location for a fixed type. It can only be assigned to values of this type. + *

+ * Used by tests. * * @param type the Java type this location must be compatible with (may be primitive) - * @param useFinal final location - * @param nonNull non-null location */ - protected Location locationForType(Class type, boolean useFinal, boolean nonNull) { - throw new UnsupportedOperationException(); - } - - /** - * Used by tests. - */ - public final Location locationForType(Class type) { - return locationForType(type, false, false); - } + public abstract Location locationForType(Class type); protected T advance(T location0) { if (location0 instanceof LocationImpl location) { @@ -1194,16 +1162,6 @@ public void visitPrimitiveField(int index, int count) { primitiveFieldSize = Math.max(primitiveFieldSize, index + count); } - public Location existingLocationForValue(Object value, Location oldLocation, ShapeImpl oldShape) { - assert oldShape.getLayout() == this.layout; - Location newLocation; - if (oldLocation.canStore(value)) { - newLocation = oldLocation; - } else { - newLocation = oldShape.allocator().locationForValueUpcast(value, oldLocation); - } - return newLocation; - } } static final class PropertyAssumptions { @@ -1228,14 +1186,32 @@ synchronized Assumption getPropertyAssumption(Object propertyName) { return assumption; } - synchronized void invalidatePropertyAssumption(Object propertyName) { + synchronized void invalidatePropertyAssumption(Object propertyName, boolean onlyExisting) { CompilerAsserts.neverPartOfCompilation(); EconomicMap map = stablePropertyAssumptions; Assumption assumption = map.get(propertyName); - if (assumption != null && assumption != Assumption.NEVER_VALID) { + if (assumption == Assumption.NEVER_VALID) { + return; + } + if (assumption != null) { assumption.invalidate("invalidatePropertyAssumption"); + } + /* + * Direct property transitions can happen only once per object as they always lead to + * new shapes, so we only need to invalidate already registered assumptions. + * + * Indirect property transitions, OTOH, can form transition cycles in the shape tree + * that may cause toggling between existing shapes for the same object, and since + * already cached shape transitions fly under the radar of future property assumptions, + * we have to block any future assumptions from being registered for this property. + */ + if (assumption != null || !onlyExisting) { map.put(propertyName, Assumption.NEVER_VALID); - propertyAssumptionsRemoved.inc(); + if (assumption != null) { + propertyAssumptionsRemoved.inc(); + } else { + propertyAssumptionsBlocked.inc(); + } } } @@ -1260,6 +1236,7 @@ Assumption getSingleContextAssumption() { static final DebugCounter shapeCacheWeakKeys = DebugCounter.create("Shape cache weak keys"); static final DebugCounter propertyAssumptionsCreated = DebugCounter.create("Property assumptions created"); static final DebugCounter propertyAssumptionsRemoved = DebugCounter.create("Property assumptions removed"); + static final DebugCounter propertyAssumptionsBlocked = DebugCounter.create("Property assumptions blocked"); static final DebugCounter transitionSingleEntriesCreated = DebugCounter.create("Transition single-entry maps created"); static final DebugCounter transitionMapsCreated = DebugCounter.create("Transition multi-entry maps created");