changeset 22288:47172a9b40ac

Object model refactoring, add Shape#defineProperty
author Andreas Woess <andreas.woess@oracle.com>
date Wed, 07 Oct 2015 19:15:14 +0200
parents 479028cce974
children cf203af4610c
files truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java truffle/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/DefaultStrategy.java truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutImpl.java truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutStrategy.java truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/PropertyImpl.java truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java
diffstat 7 files changed, 140 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java	Wed Oct 07 20:27:40 2015 +0200
+++ b/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java	Wed Oct 07 19:15:14 2015 +0200
@@ -25,6 +25,7 @@
 package com.oracle.truffle.api.object;
 
 import com.oracle.truffle.api.Assumption;
+
 import java.util.EnumSet;
 import java.util.List;
 
@@ -57,6 +58,20 @@
     public abstract Shape addProperty(Property property);
 
     /**
+     * Add or change property in the map, yielding a new or cached Shape object.
+     *
+     * @return the shape after defining the property
+     */
+    public abstract Shape defineProperty(Object key, Object value, int flags);
+
+    /**
+     * Add or change property in the map, yielding a new or cached Shape object.
+     *
+     * @return the shape after defining the property
+     */
+    public abstract Shape defineProperty(Object key, Object value, int flags, LocationFactory locationFactory);
+
+    /**
      * An {@link Iterable} over the shape's properties in insertion order.
      */
     public abstract Iterable<Property> getProperties();
--- a/truffle/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/DefaultStrategy.java	Wed Oct 07 20:27:40 2015 +0200
+++ b/truffle/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/DefaultStrategy.java	Wed Oct 07 19:15:14 2015 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.object.basic;
 
+import java.util.Objects;
+
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.Layout;
 import com.oracle.truffle.api.object.Location;
@@ -32,15 +34,16 @@
 import com.oracle.truffle.object.LocationImpl;
 import com.oracle.truffle.object.ShapeImpl;
 import com.oracle.truffle.object.ShapeImpl.BaseAllocator;
-import java.util.Objects;
 
-class DefaultStrategy implements LayoutStrategy {
+class DefaultStrategy extends LayoutStrategy {
+    @Override
     public boolean updateShape(DynamicObject object) {
         assert object.getShape().isValid();
         return false;
     }
 
-    public Shape returnCached(Shape newShape) {
+    @Override
+    public Shape ensureValid(Shape newShape) {
         assert newShape.isValid();
         return newShape;
     }
@@ -52,39 +55,33 @@
         return true;
     }
 
+    @Override
     public Shape ensureSpace(Shape shape, Location location) {
         Objects.requireNonNull(location);
         assert assertLocationInRange(shape, location);
         return shape;
     }
 
+    @Override
     public boolean isAutoExtArray() {
         return false;
     }
 
-    public Property generalizeProperty(DynamicObject object, Property oldProperty, Object value) {
-        Shape oldShape = object.getShape();
-        Location oldLocation = oldProperty.getLocation();
-        Location newLocation = ((BasicAllocator) oldShape.allocator()).locationForValueUpcast(value, oldLocation);
-        Property newProperty = oldProperty.relocate(newLocation);
-        Shape newShape = oldShape.replaceProperty(oldProperty, newProperty);
-        newProperty.setSafe(object, value, oldShape, newShape);
-        return newProperty;
-    }
-
-    public Property generalizeProperty(DynamicObject object, Property oldProperty, Object value, Shape currentShape, Shape oldNewShape) {
+    @Override
+    public ShapeAndProperty generalizeProperty(Property oldProperty, Object value, Shape currentShape, Shape nextShape) {
         Location oldLocation = oldProperty.getLocation();
         Location newLocation = ((BasicAllocator) currentShape.allocator()).locationForValueUpcast(value, oldLocation);
         Property newProperty = oldProperty.relocate(newLocation);
-        Shape newShape = oldNewShape.replaceProperty(oldProperty, newProperty);
-        newProperty.setSafe(object, value, currentShape, newShape);
-        return newProperty;
+        Shape newShape = nextShape.replaceProperty(oldProperty, newProperty);
+        return new ShapeAndProperty(newShape, newProperty);
     }
 
+    @Override
     public BaseAllocator createAllocator(Shape shape) {
         return new DefaultAllocatorImpl((ShapeImpl) shape);
     }
 
+    @Override
     public BaseAllocator createAllocator(Layout layout) {
         return new DefaultAllocatorImpl((LayoutImpl) layout);
     }
--- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java	Wed Oct 07 20:27:40 2015 +0200
+++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java	Wed Oct 07 19:15:14 2015 +0200
@@ -283,43 +283,21 @@
     @Override
     @TruffleBoundary
     public void define(Object id, Object value, int flags) {
-        ShapeImpl oldShape = getShape();
-        Property existing = oldShape.getProperty(id);
-        if (existing == null) {
-            updateShape();
-            oldShape = getShape();
-            Shape newShape = oldShape.addProperty(Property.create(id, oldShape.allocator().locationForValue(value, true, value != null), flags));
-            updateShape();
-            newShape.getLastProperty().setGeneric(this, value, oldShape, newShape);
-        } else {
-            defineExisting(id, value, flags, existing, oldShape);
-        }
-    }
-
-    private void defineExisting(Object id, Object value, int flags, Property existing, ShapeImpl oldShape) {
-        if (existing.getFlags() == flags) {
-            existing.setGeneric(this, value, null);
-        } else {
-            Property newProperty = Property.create(id, oldShape.getLayout().existingLocationForValue(value, existing.getLocation(), oldShape), flags);
-            Shape newShape = oldShape.replaceProperty(existing, newProperty);
-            this.setShapeAndResize(newShape);
-            newProperty.setInternal(this, value);
-        }
+        define(id, value, flags, ShapeImpl.DEFAULT_LAYOUT_FACTORY);
     }
 
     @Override
     @TruffleBoundary
     public void define(Object id, Object value, int flags, LocationFactory locationFactory) {
         ShapeImpl oldShape = getShape();
-        Property existing = oldShape.getProperty(id);
-        if (existing == null) {
-            updateShape();
-            oldShape = getShape();
-            Shape newShape = oldShape.addProperty(Property.create(id, locationFactory.createLocation(oldShape, value), flags));
-            updateShape();
-            newShape.getLastProperty().setGeneric(this, value, oldShape, newShape);
+        ShapeImpl newShape = oldShape.defineProperty(id, value, flags, locationFactory);
+        updateShape();
+        Property property = newShape.getProperty(id);
+
+        if (oldShape == newShape) {
+            property.setSafe(this, value, oldShape);
         } else {
-            defineExisting(id, value, flags, existing, oldShape);
+            property.setSafe(this, value, oldShape, newShape);
         }
     }
 
--- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutImpl.java	Wed Oct 07 20:27:40 2015 +0200
+++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutImpl.java	Wed Oct 07 19:15:14 2015 +0200
@@ -48,8 +48,8 @@
     private static final int INT_TO_DOUBLE_FLAG = 1;
     private static final int INT_TO_LONG_FLAG = 2;
 
-    private final LayoutStrategy strategy;
-    private final Class<? extends DynamicObject> clazz;
+    protected final LayoutStrategy strategy;
+    protected final Class<? extends DynamicObject> clazz;
     private final int allowedImplicitCasts;
 
     protected LayoutImpl(EnumSet<ImplicitCast> allowedImplicitCasts, Class<? extends DynamicObjectImpl> clazz, LayoutStrategy strategy) {
--- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutStrategy.java	Wed Oct 07 20:27:40 2015 +0200
+++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutStrategy.java	Wed Oct 07 19:15:14 2015 +0200
@@ -29,20 +29,36 @@
 import com.oracle.truffle.api.object.Shape;
 import com.oracle.truffle.object.ShapeImpl.BaseAllocator;
 
-public interface LayoutStrategy {
-    boolean updateShape(DynamicObject object);
+public abstract class LayoutStrategy {
+    public abstract boolean updateShape(DynamicObject object);
+
+    public abstract Shape ensureValid(Shape newShape);
+
+    public abstract Shape ensureSpace(Shape shape, Location location);
 
-    Shape returnCached(Shape newShape);
+    public abstract boolean isAutoExtArray();
+
+    public abstract BaseAllocator createAllocator(Layout shape);
 
-    Shape ensureSpace(Shape shape, Location location);
+    public abstract BaseAllocator createAllocator(Shape shape);
 
-    boolean isAutoExtArray();
+    protected abstract ShapeAndProperty generalizeProperty(Property oldProperty, Object value, Shape currentShape, Shape nextShape);
 
-    Property generalizeProperty(DynamicObject object, Property oldProperty, Object value);
+    public static class ShapeAndProperty {
+        private final Shape shape;
+        private final Property property;
 
-    Property generalizeProperty(DynamicObject object, Property oldProperty, Object value, Shape oldShape, Shape newShape);
+        public ShapeAndProperty(Shape shape, Property property) {
+            this.shape = shape;
+            this.property = property;
+        }
 
-    BaseAllocator createAllocator(Layout shape);
+        public Shape getShape() {
+            return shape;
+        }
 
-    BaseAllocator createAllocator(Shape shape);
+        public Property getProperty() {
+            return property;
+        }
+    }
 }
--- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/PropertyImpl.java	Wed Oct 07 20:27:40 2015 +0200
+++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/PropertyImpl.java	Wed Oct 07 19:15:14 2015 +0200
@@ -22,17 +22,16 @@
  */
 package com.oracle.truffle.object;
 
+import java.util.Objects;
+
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.FinalLocationException;
 import com.oracle.truffle.api.object.HiddenKey;
 import com.oracle.truffle.api.object.IncompatibleLocationException;
 import com.oracle.truffle.api.object.Location;
-import com.oracle.truffle.api.object.LocationModifier;
 import com.oracle.truffle.api.object.Property;
 import com.oracle.truffle.api.object.Shape;
 import com.oracle.truffle.object.Locations.DeclaredLocation;
-import java.util.EnumSet;
-import java.util.Objects;
 
 /**
  * Property objects represent the mapping between property identifiers (keys) and storage locations.
@@ -213,27 +212,32 @@
     }
 
     private void setSlowCase(DynamicObject store, Object value) {
-        if (getLocation() instanceof DeclaredLocation) {
-            setDeclaredLocation(store, value);
-        } else {
-            generalize(store, value);
+        Shape oldShape = store.getShape();
+        Shape newShape = oldShape.defineProperty(getKey(), value, getFlags());
+        if (store.updateShape()) {
+            oldShape = store.getShape();
         }
+        assert newShape.isValid() && oldShape.isValid();
+        Property newProperty = newShape.getProperty(getKey());
+        newProperty.setSafe(store, value, oldShape, newShape);
     }
 
-    private void setDeclaredLocation(DynamicObject store, Object value) {
-        store.updateShape();
-        Shape oldShape = store.getShape();
-        Shape newShape = oldShape.addProperty(this.relocateShadow(oldShape.allocator().locationForValue(value, EnumSet.of(LocationModifier.Final, LocationModifier.NonNull))));
-        store.updateShape();
-        newShape.getLastProperty().setGeneric(store, value, oldShape, newShape);
-    }
+    private void setWithShapeSlowCase(DynamicObject store, Object value, Shape currentShape, Shape nextShape) {
+        Shape oldShape = currentShape;
+        if (store.updateShape()) {
+            oldShape = store.getShape();
+        }
+        LayoutStrategy strategy = ((LayoutImpl) currentShape.getLayout()).getStrategy();
+        LayoutStrategy.ShapeAndProperty newShapeAndProperty = strategy.generalizeProperty(this, value, oldShape, nextShape);
+        if (store.updateShape()) {
+            oldShape = store.getShape();
+        }
 
-    private Property generalize(DynamicObject store, Object value) {
-        return ((LayoutImpl) store.getShape().getLayout()).getStrategy().generalizeProperty(store, this, value);
-    }
+        Shape newNextShape = newShapeAndProperty.getShape();
+        Property newProperty = newShapeAndProperty.getProperty();
 
-    private void setWithShapeSlowCase(DynamicObject store, Object value, Shape oldShape, Shape newShape) {
-        ((LayoutImpl) store.getShape().getLayout()).getStrategy().generalizeProperty(store, this, value, oldShape, newShape);
+        assert newNextShape.isValid() && oldShape.isValid();
+        newProperty.setSafe(store, value, oldShape, newNextShape);
     }
 
     @Override
@@ -246,7 +250,7 @@
         return shadow;
     }
 
-    private Property relocateShadow(Location newLocation) {
+    Property relocateShadow(Location newLocation) {
         assert !isShadow() && getLocation() instanceof DeclaredLocation && relocatable;
         return new PropertyImpl(key, newLocation, flags, true, relocatable);
     }
--- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java	Wed Oct 07 20:27:40 2015 +0200
+++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java	Wed Oct 07 19:15:14 2015 +0200
@@ -22,6 +22,16 @@
  */
 package com.oracle.truffle.object;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
 import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
@@ -34,6 +44,7 @@
 import com.oracle.truffle.api.object.DynamicObjectFactory;
 import com.oracle.truffle.api.object.Layout;
 import com.oracle.truffle.api.object.Location;
+import com.oracle.truffle.api.object.LocationFactory;
 import com.oracle.truffle.api.object.ObjectLocation;
 import com.oracle.truffle.api.object.ObjectType;
 import com.oracle.truffle.api.object.Property;
@@ -53,15 +64,6 @@
 import com.oracle.truffle.object.Transition.PropertyTransition;
 import com.oracle.truffle.object.Transition.RemovePropertyTransition;
 import com.oracle.truffle.object.Transition.ReservePrimitiveArrayTransition;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Shape objects create a mapping of Property objects to indexes. The mapping of those indexes to an
@@ -312,7 +314,7 @@
         ShapeImpl cachedShape = this.getTransitionMapForRead().get(transition);
         if (cachedShape != null) { // Shape already exists?
             shapeCacheHitCount.inc();
-            return (ShapeImpl) layout.getStrategy().returnCached(cachedShape);
+            return (ShapeImpl) layout.getStrategy().ensureValid(cachedShape);
         }
         shapeCacheMissCount.inc();
 
@@ -339,6 +341,40 @@
         }
     }
 
+    @TruffleBoundary
+    @Override
+    public ShapeImpl defineProperty(Object key, Object value, int flags) {
+        return defineProperty(key, value, flags, DEFAULT_LAYOUT_FACTORY);
+    }
+
+    @TruffleBoundary
+    @Override
+    public ShapeImpl defineProperty(Object key, Object value, int flags, LocationFactory locationFactory) {
+        ShapeImpl oldShape = this;
+        if (!oldShape.isValid()) {
+            oldShape = (ShapeImpl) layout.getStrategy().ensureValid(oldShape);
+        }
+        PropertyImpl existing = (PropertyImpl) oldShape.getProperty(key);
+        if (existing == null) {
+            return oldShape.addProperty(Property.create(key, locationFactory.createLocation(oldShape, value), flags));
+        } else {
+            if (existing.getFlags() == flags) {
+                if (existing.getLocation().canSet(value)) {
+                    return oldShape;
+                } else {
+                    if (existing.getLocation() instanceof DeclaredLocation) {
+                        return oldShape.addProperty(existing.relocateShadow(locationFactory.createLocation(oldShape, value)));
+                    } else {
+                        return (ShapeImpl) layout.getStrategy().generalizeProperty(existing, value, oldShape, oldShape).getShape();
+                    }
+                }
+            } else {
+                Property newProperty = Property.create(key, oldShape.getLayout().existingLocationForValue(value, existing.getLocation(), oldShape), flags);
+                return oldShape.replaceProperty(existing, newProperty);
+            }
+        }
+    }
+
     /**
      * Add a new property in the map, yielding a new or cached Shape object.
      *
@@ -1105,6 +1141,12 @@
         }
     };
 
+    static final LocationFactory DEFAULT_LAYOUT_FACTORY = new LocationFactory() {
+        public Location createLocation(Shape shape, Object value) {
+            return ((ShapeImpl) shape).allocator().locationForValue(value, true, value != null);
+        }
+    };
+
     private static final DebugCounter shapeCount = DebugCounter.create("Shapes allocated total");
     private static final DebugCounter shapeCloneCount = DebugCounter.create("Shapes allocated cloned");
     private static final DebugCounter shapeCacheHitCount = DebugCounter.create("Shape cache hits");