diff graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java @ 18412:997bc9764a9a

SL: use the truffle object storage model to represent SL objects
author Andreas Woess <andreas.woess@jku.at>
date Tue, 18 Nov 2014 12:08:51 +0100
parents
children f7bc60c3a8f6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java	Tue Nov 18 12:08:51 2014 +0100
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.access;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.object.*;
+
+/**
+ * The node for accessing a property of an object. When executed, this node first evaluates the
+ * object expression on the left side of the dot operator and then reads the named property.
+ */
+public abstract class SLWritePropertyCacheNode extends Node {
+
+    public static SLWritePropertyCacheNode create(String propertyName) {
+        return new SLUninitializedWritePropertyNode(propertyName);
+    }
+
+    public abstract void executeObject(DynamicObject receiver, Object value);
+
+    public abstract void executeLong(DynamicObject receiver, long value);
+
+    public abstract void executeBoolean(DynamicObject receiver, boolean value);
+
+    protected abstract static class SLWritePropertyCacheChainNode extends SLWritePropertyCacheNode {
+        protected final Shape oldShape;
+        protected final Shape newShape;
+        @Child protected SLWritePropertyCacheNode next;
+
+        public SLWritePropertyCacheChainNode(Shape oldShape, Shape newShape, SLWritePropertyCacheNode next) {
+            this.oldShape = oldShape;
+            this.newShape = newShape;
+            this.next = next;
+        }
+
+        @Override
+        public final void executeObject(DynamicObject receiver, Object value) {
+            try {
+                // if this assumption fails, the object needs to be updated to a valid shape
+                oldShape.getValidAssumption().check();
+                newShape.getValidAssumption().check();
+            } catch (InvalidAssumptionException e) {
+                this.replace(next).executeObject(receiver, value);
+                return;
+            }
+
+            boolean condition = oldShape.check(receiver) && checkValue(receiver, value);
+
+            if (condition) {
+                executeObjectUnchecked(receiver, value);
+            } else {
+                next.executeObject(receiver, value);
+            }
+        }
+
+        @Override
+        public final void executeLong(DynamicObject receiver, long value) {
+            try {
+                // if this assumption fails, the object needs to be updated to a valid shape
+                oldShape.getValidAssumption().check();
+                newShape.getValidAssumption().check();
+            } catch (InvalidAssumptionException e) {
+                this.replace(next).executeLong(receiver, value);
+                return;
+            }
+
+            boolean condition = oldShape.check(receiver) && checkValue(receiver, value);
+
+            if (condition) {
+                executeLongUnchecked(receiver, value);
+            } else {
+                next.executeLong(receiver, value);
+            }
+        }
+
+        @Override
+        public final void executeBoolean(DynamicObject receiver, boolean value) {
+            try {
+                // if this assumption fails, the object needs to be updated to a valid shape
+                oldShape.getValidAssumption().check();
+                newShape.getValidAssumption().check();
+            } catch (InvalidAssumptionException e) {
+                this.replace(next).executeBoolean(receiver, value);
+                return;
+            }
+
+            boolean condition = oldShape.check(receiver) && checkValue(receiver, value);
+
+            if (condition) {
+                executeBooleanUnchecked(receiver, value);
+            } else {
+                next.executeBoolean(receiver, value);
+            }
+        }
+
+        @SuppressWarnings("unused")
+        protected boolean checkValue(DynamicObject receiver, Object value) {
+            return true;
+        }
+
+        protected abstract void executeObjectUnchecked(DynamicObject receiver, Object value);
+
+        protected void executeLongUnchecked(DynamicObject receiver, long value) {
+            executeObjectUnchecked(receiver, value);
+        }
+
+        protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) {
+            executeObjectUnchecked(receiver, value);
+        }
+    }
+
+    protected static class SLWriteObjectPropertyNode extends SLWritePropertyCacheChainNode {
+        private final Location location;
+
+        protected SLWriteObjectPropertyNode(Shape oldShape, Shape newShape, Location location, SLWritePropertyCacheNode next) {
+            super(oldShape, newShape, next);
+            this.location = location;
+        }
+
+        @Override
+        protected void executeObjectUnchecked(DynamicObject receiver, Object value) {
+            try {
+                if (oldShape == newShape) {
+                    location.set(receiver, value, oldShape);
+                } else {
+                    location.set(receiver, value, oldShape, newShape);
+                }
+            } catch (IncompatibleLocationException | FinalLocationException e) {
+                replace(next).executeObject(receiver, value);
+            }
+        }
+
+        @Override
+        protected boolean checkValue(DynamicObject receiver, Object value) {
+            return location.canSet(receiver, value);
+        }
+    }
+
+    protected static class SLWriteBooleanPropertyNode extends SLWritePropertyCacheChainNode {
+        private final BooleanLocation location;
+
+        protected SLWriteBooleanPropertyNode(Shape oldShape, Shape newShape, BooleanLocation location, SLWritePropertyCacheNode next) {
+            super(oldShape, newShape, next);
+            this.location = location;
+        }
+
+        @Override
+        protected void executeObjectUnchecked(DynamicObject receiver, Object value) {
+            try {
+                if (oldShape == newShape) {
+                    location.set(receiver, value, oldShape);
+                } else {
+                    location.set(receiver, value, oldShape, newShape);
+                }
+            } catch (IncompatibleLocationException | FinalLocationException e) {
+                replace(next).executeObject(receiver, value);
+            }
+        }
+
+        @Override
+        protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) {
+            try {
+                if (oldShape == newShape) {
+                    location.setBoolean(receiver, value, oldShape);
+                } else {
+                    location.setBoolean(receiver, value, oldShape, newShape);
+                }
+            } catch (FinalLocationException e) {
+                replace(next).executeBoolean(receiver, value);
+            }
+        }
+
+        @Override
+        protected boolean checkValue(DynamicObject receiver, Object value) {
+            return value instanceof Boolean;
+        }
+    }
+
+    protected static class SLWriteLongPropertyNode extends SLWritePropertyCacheChainNode {
+        private final LongLocation location;
+
+        protected SLWriteLongPropertyNode(Shape oldShape, Shape newShape, LongLocation location, SLWritePropertyCacheNode next) {
+            super(oldShape, newShape, next);
+            this.location = location;
+        }
+
+        @Override
+        protected void executeObjectUnchecked(DynamicObject receiver, Object value) {
+            try {
+                if (oldShape == newShape) {
+                    location.set(receiver, value, oldShape);
+                } else {
+                    location.set(receiver, value, oldShape, newShape);
+                }
+            } catch (IncompatibleLocationException | FinalLocationException e) {
+                replace(next).executeObject(receiver, value);
+            }
+        }
+
+        @Override
+        protected void executeLongUnchecked(DynamicObject receiver, long value) {
+            try {
+                if (oldShape == newShape) {
+                    location.setLong(receiver, value, oldShape);
+                } else {
+                    location.setLong(receiver, value, oldShape, newShape);
+                }
+            } catch (FinalLocationException e) {
+                replace(next).executeLong(receiver, value);
+            }
+        }
+
+        @Override
+        protected boolean checkValue(DynamicObject receiver, Object value) {
+            return value instanceof Long;
+        }
+    }
+
+    protected static class SLUninitializedWritePropertyNode extends SLWritePropertyCacheNode {
+        protected final String propertyName;
+
+        protected SLUninitializedWritePropertyNode(String propertyName) {
+            this.propertyName = propertyName;
+        }
+
+        @Override
+        public void executeObject(DynamicObject receiver, Object value) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+
+            if (receiver.updateShape()) {
+                // shape changed, retry cache again
+                getTopNode().executeObject(receiver, value);
+                return;
+            }
+
+            Shape oldShape = receiver.getShape();
+            Shape newShape;
+            Property property = oldShape.getProperty(propertyName);
+
+            final SLWritePropertyCacheNode resolvedNode;
+            if (property != null && property.getLocation().canSet(receiver, value)) {
+                newShape = oldShape;
+            } else {
+                receiver.define(propertyName, value, 0);
+                newShape = receiver.getShape();
+                property = newShape.getProperty(propertyName);
+            }
+
+            if (property.getLocation() instanceof LongLocation) {
+                resolvedNode = new SLWriteLongPropertyNode(oldShape, newShape, (LongLocation) property.getLocation(), this);
+            } else if (property.getLocation() instanceof BooleanLocation) {
+                resolvedNode = new SLWriteBooleanPropertyNode(oldShape, newShape, (BooleanLocation) property.getLocation(), this);
+            } else {
+                resolvedNode = new SLWriteObjectPropertyNode(oldShape, newShape, property.getLocation(), this);
+            }
+
+            this.replace(resolvedNode, "resolved '" + propertyName + "'").executeObject(receiver, value);
+        }
+
+        private SLWritePropertyCacheNode getTopNode() {
+            SLWritePropertyCacheNode top = this;
+            while (top.getParent() instanceof SLWritePropertyCacheNode) {
+                top = (SLWritePropertyCacheNode) top.getParent();
+            }
+            return top;
+        }
+
+        @Override
+        public void executeLong(DynamicObject receiver, long value) {
+            executeObject(receiver, value);
+        }
+
+        @Override
+        public void executeBoolean(DynamicObject receiver, boolean value) {
+            executeObject(receiver, value);
+        }
+    }
+}