changeset 22353:56e71849d356

Merging eval instrument with parameters
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Fri, 06 Nov 2015 20:54:49 +0100
parents 536c5b85fe1d (diff) 7d9b7365b675 (current diff)
children 0ad8cb1608be
files truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeInstrument.java
diffstat 25 files changed, 403 insertions(+), 330 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.java	Fri Nov 06 20:54:49 2015 +0100
@@ -42,6 +42,7 @@
 import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheFieldFactory;
 import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheMethodFactory;
 import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheNodeFieldFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCachesOrderFactory;
 import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestGuardWithCachedAndDynamicParameterFactory;
 import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestGuardWithJustCachedParameterFactory;
 import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestMultipleCachesFactory;
@@ -309,6 +310,35 @@
     }
 
     @NodeChild
+    static class TestCachesOrder extends ValueNode {
+
+        @Specialization(guards = "boundByGuard != 0")
+        static int do1(int value, //
+                        @Cached("get(value)") int intermediateValue, //
+                        @Cached("transform(intermediateValue)") int boundByGuard, //
+                        @Cached("new()") Object notBoundByGuards) {
+            return intermediateValue;
+        }
+
+        protected int get(int i) {
+            return i * 2;
+        }
+
+        protected int transform(int i) {
+            return i * 3;
+        }
+
+    }
+
+    @Test
+    public void testCachesOrder() {
+        CallTarget root = createCallTarget(TestCachesOrderFactory.getInstance());
+        assertEquals(42, root.call(21));
+        assertEquals(42, root.call(22));
+        assertEquals(42, root.call(23));
+    }
+
+    @NodeChild
     static class CachedError1 extends ValueNode {
         @Specialization
         static int do1(int value, @ExpectError("Incompatible return type int. The expression type must be equal to the parameter type double.")//
--- a/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Layout.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Layout.java	Fri Nov 06 20:54:49 2015 +0100
@@ -121,6 +121,7 @@
      */
     public static final class Builder {
         private EnumSet<ImplicitCast> allowedImplicitCasts;
+        private boolean polymorphicUnboxing;
 
         /**
          * Create a new layout builder.
@@ -155,9 +156,21 @@
             this.allowedImplicitCasts.add(allowedImplicitCast);
             return this;
         }
+
+        /**
+         * If {@code true}, try to keep properties with polymorphic primitive types unboxed.
+         */
+        public Builder setPolymorphicUnboxing(boolean polymorphicUnboxing) {
+            this.polymorphicUnboxing = polymorphicUnboxing;
+            return this;
+        }
     }
 
     protected static EnumSet<ImplicitCast> getAllowedImplicitCasts(Builder builder) {
         return builder.allowedImplicitCasts;
     }
+
+    protected static boolean getPolymorphicUnboxing(Builder builder) {
+        return builder.polymorphicUnboxing;
+    }
 }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Fri Nov 06 20:54:49 2015 +0100
@@ -243,10 +243,9 @@
                     leaveCount++;
                 }
 
-                public void onReturnExceptional(Probe p, Exception exception) {
+                public void onReturnExceptional(Probe p, Throwable exception) {
                     leaveCount++;
                 }
-
             }, "Instrumentation Test Counter");
         }
 
@@ -296,10 +295,9 @@
                     leaveCount++;
                 }
 
-                public void onReturnExceptional(Probe p, Node node, VirtualFrame vFrame, Exception exception) {
+                public void onReturnExceptional(Probe p, Node node, VirtualFrame vFrame, Throwable exception) {
                     leaveCount++;
                 }
-
             }, "Instrumentation Test Counter");
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Fri Nov 06 20:54:49 2015 +0100
@@ -26,7 +26,6 @@
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.EventHandlerNode;
 import com.oracle.truffle.api.instrument.Instrumenter;
-import com.oracle.truffle.api.instrument.KillException;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.WrapperNode;
 import com.oracle.truffle.api.nodes.Node;
@@ -81,8 +80,6 @@
             try {
                 result = child.execute(vFrame);
                 eventHandlerNode.returnValue(child, vFrame, result);
-            } catch (KillException e) {
-                throw (e);
             } catch (Exception e) {
                 eventHandlerNode.returnExceptional(child, vFrame, e);
                 throw (e);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/ComputeInExecutor.java	Fri Nov 06 20:54:49 2015 +0100
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014, 2015, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.api.vm;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.concurrent.Executor;
+
+abstract class ComputeInExecutor<R> implements Runnable {
+    private final Executor executor;
+    private R result;
+    private Throwable exception;
+    private boolean started;
+    private boolean done;
+
+    protected ComputeInExecutor(Executor executor) {
+        this.executor = executor;
+    }
+
+    protected abstract R compute() throws IOException;
+
+    public final R get() throws IOException {
+        perform();
+        if (executor != null) {
+            waitForDone();
+        }
+        exceptionCheck();
+        return result;
+    }
+
+    private void waitForDone() throws InterruptedIOException {
+        synchronized (this) {
+            while (!done) {
+                try {
+                    wait();
+                } catch (InterruptedException ex) {
+                    throw new InterruptedIOException(ex.getMessage());
+                }
+            }
+        }
+    }
+
+    private void exceptionCheck() throws IOException, RuntimeException {
+        if (exception instanceof IOException) {
+            throw (IOException) exception;
+        }
+        if (exception instanceof RuntimeException) {
+            throw (RuntimeException) exception;
+        }
+        if (exception != null) {
+            throw new RuntimeException(exception);
+        }
+    }
+
+    public final void perform() throws IOException {
+        if (started) {
+            return;
+        }
+        started = true;
+        if (executor == null) {
+            run();
+        } else {
+            executor.execute(this);
+        }
+        exceptionCheck();
+    }
+
+    @Override
+    public final void run() {
+        try {
+            result = compute();
+        } catch (Exception ex) {
+            exception = ex;
+        } finally {
+            if (executor != null) {
+                synchronized (this) {
+                    done = true;
+                    notifyAll();
+                }
+            } else {
+                done = true;
+            }
+        }
+    }
+
+    @Override
+    public final String toString() {
+        return "value=" + result + ",exception=" + exception + ",computed=" + done;
+    }
+}
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java	Fri Nov 06 20:54:49 2015 +0100
@@ -27,7 +27,6 @@
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -38,9 +37,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.oracle.truffle.api.CallTarget;
@@ -64,6 +61,7 @@
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.Source;
+import java.util.logging.Level;
 
 /**
  * Gate way into the world of {@link TruffleLanguage Truffle languages}. {@link #buildNew()
@@ -103,13 +101,6 @@
 @SuppressWarnings("rawtypes")
 public class PolyglotEngine {
     static final boolean JAVA_INTEROP_ENABLED = !TruffleOptions.AOT;
-    private static final Executor DIRECT_EXECUTOR = new Executor() {
-        @Override
-        public void execute(Runnable command) {
-            command.run();
-        }
-    };
-
     static final Logger LOG = Logger.getLogger(PolyglotEngine.class.getName());
     private static final SPIAccessor SPI = new SPIAccessor();
     private final Thread initThread;
@@ -292,7 +283,7 @@
          */
         public Builder globalSymbol(String name, Object obj) {
             final Object truffleReady;
-            if (obj instanceof Number || obj instanceof String || obj instanceof Character || obj instanceof Boolean) {
+            if (obj instanceof TruffleObject || obj instanceof Number || obj instanceof String || obj instanceof Character || obj instanceof Boolean) {
                 truffleReady = obj;
             } else {
                 if (JAVA_INTEROP_ENABLED) {
@@ -342,8 +333,7 @@
             if (in == null) {
                 in = System.in;
             }
-            Executor nonNullExecutor = executor != null ? executor : DIRECT_EXECUTOR;
-            return new PolyglotEngine(nonNullExecutor, globals, out, err, in, handlers.toArray(new EventConsumer[0]));
+            return new PolyglotEngine(executor, globals, out, err, in, handlers.toArray(new EventConsumer[0]));
         }
     }
 
@@ -388,9 +378,9 @@
     public void dispose() {
         checkThread();
         disposed = true;
-        executor.execute(new Runnable() {
+        ComputeInExecutor<Void> compute = new ComputeInExecutor<Void>(executor) {
             @Override
-            public void run() {
+            protected Void compute() throws IOException {
                 for (Language language : getLanguages().values()) {
                     TruffleLanguage<?> impl = language.getImpl(false);
                     if (impl != null) {
@@ -401,26 +391,26 @@
                         }
                     }
                 }
+                return null;
             }
-        });
+        };
+        try {
+            compute.perform();
+        } catch (IOException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     private Value eval(final Language l, final Source s) throws IOException {
-        final Object[] result = {null, null};
-        final CountDownLatch ready = new CountDownLatch(1);
         final TruffleLanguage[] lang = {null};
-        executor.execute(new Runnable() {
+        ComputeInExecutor<Object> compute = new ComputeInExecutor<Object>(executor) {
             @Override
-            public void run() {
-                evalImpl(lang, s, result, l, ready);
+            protected Object compute() throws IOException {
+                return evalImpl(lang, s, l);
             }
-        });
-        exceptionCheck(result);
-        return createValue(lang, result, ready);
-    }
-
-    Value createValue(TruffleLanguage[] lang, Object[] result, CountDownLatch ready) {
-        return new Value(lang, result, ready);
+        };
+        compute.perform();
+        return new Value(lang, compute);
     }
 
     Language createLanguage(Map.Entry<String, LanguageCache> en) {
@@ -428,62 +418,48 @@
     }
 
     @SuppressWarnings("try")
-    private void evalImpl(TruffleLanguage<?>[] fillLang, Source s, Object[] result, Language l, CountDownLatch ready) {
+    private Object evalImpl(TruffleLanguage<?>[] fillLang, Source s, Language l) throws IOException {
         try (Closeable d = SPI.executionStart(this, -1, debugger, s)) {
             TruffleLanguage<?> langImpl = l.getImpl(true);
             fillLang[0] = langImpl;
-            result[0] = SPI.eval(langImpl, s);
-        } catch (IOException ex) {
-            result[1] = ex;
-        } finally {
-            ready.countDown();
+            return SPI.eval(langImpl, s);
         }
     }
 
     @SuppressWarnings("try")
     final Object invokeForeign(final Node foreignNode, VirtualFrame frame, final TruffleObject receiver) throws IOException {
-        final Object[] res = {null, null};
-        if (executor == DIRECT_EXECUTOR) {
+        Object res;
+        if (executor == null) {
             try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) {
                 final Object[] args = ForeignAccess.getArguments(frame).toArray();
-                res[0] = ForeignAccess.execute(foreignNode, frame, receiver, args);
+                res = ForeignAccess.execute(foreignNode, frame, receiver, args);
             }
         } else {
-            invokeForeignOnExecutor(foreignNode, frame, receiver, res);
+            res = invokeForeignOnExecutor(foreignNode, frame, receiver);
         }
-        exceptionCheck(res);
-        if (res[0] instanceof TruffleObject) {
-            return new EngineTruffleObject(this, (TruffleObject) res[0]);
+        if (res instanceof TruffleObject) {
+            return new EngineTruffleObject(this, (TruffleObject) res);
         } else {
-            return res[0];
+            return res;
         }
     }
 
     @TruffleBoundary
-    private void invokeForeignOnExecutor(final Node foreignNode, VirtualFrame frame, final TruffleObject receiver, final Object[] res) throws IOException {
+    private Object invokeForeignOnExecutor(final Node foreignNode, VirtualFrame frame, final TruffleObject receiver) throws IOException {
         final MaterializedFrame materialized = frame.materialize();
-        final CountDownLatch computed = new CountDownLatch(1);
-        executor.execute(new Runnable() {
+        ComputeInExecutor<Object> compute = new ComputeInExecutor<Object>(executor) {
             @SuppressWarnings("try")
             @Override
-            public void run() {
+            protected Object compute() throws IOException {
                 try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) {
                     final Object[] args = ForeignAccess.getArguments(materialized).toArray();
                     RootNode node = SymbolInvokerImpl.createTemporaryRoot(TruffleLanguage.class, foreignNode, receiver, args.length);
                     final CallTarget target = Truffle.getRuntime().createCallTarget(node);
-                    res[0] = target.call(args);
-                } catch (Exception ex) {
-                    res[1] = ex;
-                } finally {
-                    computed.countDown();
+                    return target.call(args);
                 }
             }
-        });
-        try {
-            computed.await();
-        } catch (InterruptedException ex) {
-            throw new InterruptedIOException(ex.getMessage());
-        }
+        };
+        return compute.get();
     }
 
     /**
@@ -506,54 +482,48 @@
     public Value findGlobalSymbol(final String globalName) {
         checkThread();
         final TruffleLanguage<?>[] lang = {null};
-        final Object[] obj = {globals.get(globalName), null};
-        final CountDownLatch ready = new CountDownLatch(1);
-        if (obj[0] == null) {
-            executor.execute(new Runnable() {
-                @Override
-                public void run() {
-                    findGlobalSymbolImpl(obj, globalName, lang, ready);
+        ComputeInExecutor<Object> compute = new ComputeInExecutor<Object>(executor) {
+            @Override
+            protected Object compute() throws IOException {
+                Object obj = globals.get(globalName);
+                if (obj == null) {
+                    for (Language dl : langs.values()) {
+                        TruffleLanguage.Env env = dl.getEnv(false);
+                        if (env == null) {
+                            continue;
+                        }
+                        obj = SPI.findExportedSymbol(env, globalName, true);
+                        if (obj != null) {
+                            lang[0] = dl.getImpl(true);
+                            break;
+                        }
+                    }
                 }
-            });
-            try {
-                ready.await();
-            } catch (InterruptedException ex) {
-                LOG.log(Level.SEVERE, null, ex);
+                if (obj == null) {
+                    for (Language dl : langs.values()) {
+                        TruffleLanguage.Env env = dl.getEnv(false);
+                        if (env == null) {
+                            continue;
+                        }
+                        obj = SPI.findExportedSymbol(env, globalName, true);
+                        if (obj != null) {
+                            lang[0] = dl.getImpl(true);
+                            break;
+                        }
+                    }
+                }
+                return obj;
             }
-        } else {
-            ready.countDown();
+        };
+        try {
+            compute.perform();
+            if (compute.get() == null) {
+                return null;
+            }
+        } catch (IOException ex) {
+            // OK, go on
         }
-        return obj[0] == null ? null : createValue(lang, obj, ready);
-    }
-
-    private void findGlobalSymbolImpl(Object[] obj, String globalName, TruffleLanguage<?>[] lang, CountDownLatch ready) {
-        if (obj[0] == null) {
-            for (Language dl : langs.values()) {
-                TruffleLanguage.Env env = dl.getEnv(false);
-                if (env == null) {
-                    continue;
-                }
-                obj[0] = SPI.findExportedSymbol(env, globalName, true);
-                if (obj[0] != null) {
-                    lang[0] = dl.getImpl(true);
-                    break;
-                }
-            }
-        }
-        if (obj[0] == null) {
-            for (Language dl : langs.values()) {
-                TruffleLanguage.Env env = dl.getEnv(false);
-                if (env == null) {
-                    continue;
-                }
-                obj[0] = SPI.findExportedSymbol(env, globalName, true);
-                if (obj[0] != null) {
-                    lang[0] = dl.getImpl(true);
-                    break;
-                }
-            }
-        }
-        ready.countDown();
+        return new Value(lang, compute);
     }
 
     private void checkThread() {
@@ -594,15 +564,6 @@
         }
     }
 
-    static void exceptionCheck(Object[] result) throws RuntimeException, IOException {
-        if (result[1] instanceof IOException) {
-            throw (IOException) result[1];
-        }
-        if (result[1] instanceof RuntimeException) {
-            throw (RuntimeException) result[1];
-        }
-    }
-
     /**
      * A future value wrapper. A user level wrapper around values returned by evaluation of various
      * {@link PolyglotEngine} functions like
@@ -616,14 +577,22 @@
      */
     public class Value {
         private final TruffleLanguage<?>[] language;
-        private final Object[] result;
-        private final CountDownLatch ready;
+        private final ComputeInExecutor<Object> compute;
         private CallTarget target;
 
-        Value(TruffleLanguage<?>[] language, Object[] result, CountDownLatch ready) {
+        Value(TruffleLanguage<?>[] language, ComputeInExecutor<Object> compute) {
+            this.language = language;
+            this.compute = compute;
+        }
+
+        Value(TruffleLanguage<?>[] language, final Object value) {
             this.language = language;
-            this.result = result;
-            this.ready = ready;
+            this.compute = new ComputeInExecutor<Object>(null) {
+                @Override
+                protected Object compute() throws IOException {
+                    return value;
+                }
+            };
         }
 
         /**
@@ -636,12 +605,11 @@
          * @throws IOException in case it is not possible to obtain the value of the object
          */
         public Object get() throws IOException {
-            waitForSymbol();
-            exceptionCheck(result);
-            if (result[0] instanceof TruffleObject) {
-                return new EngineTruffleObject(PolyglotEngine.this, (TruffleObject) result[0]);
+            Object result = waitForSymbol();
+            if (result instanceof TruffleObject) {
+                return new EngineTruffleObject(PolyglotEngine.this, (TruffleObject) result);
             } else {
-                return result[0];
+                return result;
             }
         }
 
@@ -700,67 +668,48 @@
          */
         public Value invoke(final Object thiz, final Object... args) throws IOException {
             get();
-            final CountDownLatch done = new CountDownLatch(1);
-            final Object[] res = {null, null};
-            executor.execute(new Runnable() {
+            ComputeInExecutor<Object> invokeCompute = new ComputeInExecutor<Object>(executor) {
+                @SuppressWarnings("try")
                 @Override
-                public void run() {
-                    invokeImpl(thiz, args, res, done);
-                }
-            });
-            exceptionCheck(res);
-            return createValue(language, res, done);
-        }
-
-        @SuppressWarnings("try")
-        private void invokeImpl(Object thiz, Object[] args, Object[] res, CountDownLatch done) {
-            try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) {
-                List<Object> arr = new ArrayList<>();
-                if (thiz == null) {
-                    if (language[0] != null) {
-                        Object global = SPI.languageGlobal(SPI.findLanguage(PolyglotEngine.this, language[0].getClass()));
-                        if (global != null) {
-                            arr.add(global);
+                protected Object compute() throws IOException {
+                    try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) {
+                        List<Object> arr = new ArrayList<>();
+                        if (thiz == null) {
+                            if (language[0] != null) {
+                                Object global = SPI.languageGlobal(SPI.findLanguage(PolyglotEngine.this, language[0].getClass()));
+                                if (global != null) {
+                                    arr.add(global);
+                                }
+                            }
+                        } else {
+                            arr.add(thiz);
+                        }
+                        arr.addAll(Arrays.asList(args));
+                        for (;;) {
+                            try {
+                                if (target == null) {
+                                    target = SymbolInvokerImpl.createCallTarget(language[0], compute.get(), arr.toArray());
+                                }
+                                return target.call(arr.toArray());
+                            } catch (ArgumentsMishmashException ex) {
+                                target = null;
+                            }
                         }
                     }
-                } else {
-                    arr.add(thiz);
                 }
-                arr.addAll(Arrays.asList(args));
-                for (;;) {
-                    try {
-                        if (target == null) {
-                            target = SymbolInvokerImpl.createCallTarget(language[0], result[0], arr.toArray());
-                        }
-                        res[0] = target.call(arr.toArray());
-                        break;
-                    } catch (ArgumentsMishmashException ex) {
-                        target = null;
-                    }
-                }
-            } catch (IOException ex) {
-                res[1] = ex;
-            } catch (RuntimeException ex) {
-                res[1] = ex;
-            } finally {
-                done.countDown();
-            }
+            };
+            invokeCompute.perform();
+            return new Value(language, invokeCompute);
         }
 
-        private void waitForSymbol() throws InterruptedIOException {
+        private Object waitForSymbol() throws IOException {
             checkThread();
-            try {
-                if (ready != null) {
-                    ready.await();
-                }
-            } catch (InterruptedException ex) {
-                throw (InterruptedIOException) new InterruptedIOException(ex.getMessage()).initCause(ex);
-            }
+            return compute.get();
         }
 
         @Override
         public String toString() {
-            return "PolyglotEngine.Value[value=" + result[0] + ",exception=" + result[1] + ",computed=" + (ready.getCount() == 0) + "]";
+            return "PolyglotEngine.Value[" + compute + "]";
         }
     }
 
@@ -834,8 +783,8 @@
         public Value getGlobalObject() {
             checkThread();
 
-            Object[] res = {SPI.languageGlobal(getEnv(true)), null};
-            return res[0] == null ? null : new Value(new TruffleLanguage[]{info.getImpl(true)}, res, null);
+            Object res = SPI.languageGlobal(getEnv(true));
+            return res == null ? null : new Value(new TruffleLanguage[]{info.getImpl(true)}, res);
         }
 
         TruffleLanguage<?> getImpl(boolean create) {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java	Fri Nov 06 20:54:49 2015 +0100
@@ -423,7 +423,7 @@
                     doHalt(node, vFrame.materialize());
                 }
 
-                public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) {
+                public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Throwable exception) {
                     doHalt(node, vFrame.materialize());
                 }
 
@@ -481,7 +481,7 @@
                     doHalt(node, vFrame.materialize());
                 }
 
-                public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) {
+                public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Throwable exception) {
                     doHalt(node, vFrame.materialize());
                 }
 
@@ -564,7 +564,7 @@
                     doHalt(node, vFrame.materialize());
                 }
 
-                public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) {
+                public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Throwable exception) {
                     doHalt(node, vFrame.materialize());
                 }
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/EventHandlerNode.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/EventHandlerNode.java	Fri Nov 06 20:54:49 2015 +0100
@@ -54,7 +54,7 @@
     /**
      * An AST Node's execute method has just thrown an exception.
      */
-    public abstract void returnExceptional(Node node, VirtualFrame vFrame, Exception exception);
+    public abstract void returnExceptional(Node node, VirtualFrame vFrame, Throwable exception);
 
     /**
      * Gets the {@link Probe} that manages this chain of event handling.
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeInstrument.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeInstrument.java	Fri Nov 06 20:54:49 2015 +0100
@@ -220,7 +220,7 @@
             }
 
             @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+            public void returnExceptional(Node node, VirtualFrame vFrame, Throwable exception) {
                 SimpleInstrument.this.simpleListener.onReturnExceptional(SimpleInstrument.this.probe, exception);
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnExceptional(node, vFrame, exception);
@@ -312,7 +312,7 @@
             }
 
             @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+            public void returnExceptional(Node node, VirtualFrame vFrame, Throwable exception) {
                 standardListener.onReturnExceptional(StandardInstrument.this.probe, node, vFrame, exception);
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnExceptional(node, vFrame, exception);
@@ -438,7 +438,7 @@
             }
 
             @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+            public void returnExceptional(Node node, VirtualFrame vFrame, Throwable exception) {
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnExceptional(node, vFrame, exception);
                 }
@@ -525,7 +525,7 @@
             }
 
             @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+            public void returnExceptional(Node node, VirtualFrame vFrame, Throwable exception) {
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnExceptional(node, vFrame, exception);
                 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Fri Nov 06 20:54:49 2015 +0100
@@ -110,7 +110,13 @@
     }
 
     @Override
-    public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+    public void returnExceptional(Node node, VirtualFrame vFrame, Throwable exception) {
+        if (exception instanceof KillException) {
+            throw (KillException) exception;
+        }
+        if (exception instanceof QuitException) {
+            throw (QuitException) exception;
+        }
         this.probe.checkProbeUnchanged();
         if (firstInstrumentNode != null) {
             firstInstrumentNode.returnExceptional(node, vFrame, exception);
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java	Fri Nov 06 20:54:49 2015 +0100
@@ -74,5 +74,5 @@
      * <p>
      * <strong>Synchronous</strong>: Truffle execution waits until the call returns.
      */
-    void onReturnExceptional(Probe probe, Exception exception);
+    void onReturnExceptional(Probe probe, Throwable exception);
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardAfterInstrumentListener.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardAfterInstrumentListener.java	Fri Nov 06 20:54:49 2015 +0100
@@ -68,5 +68,5 @@
      * <p>
      * <strong>Synchronous</strong>: Truffle execution waits until the call returns.
      */
-    void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception);
+    void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Throwable exception);
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java	Fri Nov 06 20:54:49 2015 +0100
@@ -74,5 +74,5 @@
      * <p>
      * <strong>Synchronous</strong>: Truffle execution waits until the call returns.
      */
-    void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception);
+    void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Throwable exception);
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultSimpleInstrumentListener.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultSimpleInstrumentListener.java	Fri Nov 06 20:54:49 2015 +0100
@@ -41,6 +41,6 @@
     public void onReturnValue(Probe probe, Object result) {
     }
 
-    public void onReturnExceptional(Probe probe, Exception exception) {
+    public void onReturnExceptional(Probe probe, Throwable exception) {
     }
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultStandardInstrumentListener.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultStandardInstrumentListener.java	Fri Nov 06 20:54:49 2015 +0100
@@ -44,7 +44,6 @@
     public void onReturnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) {
     }
 
-    public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) {
+    public void onReturnExceptional(Probe probe, Node node, VirtualFrame vFrame, Throwable exception) {
     }
-
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Fri Nov 06 20:54:49 2015 +0100
@@ -319,7 +319,7 @@
             for (Map.Entry<String, Object> property : node.getProperties().entrySet()) {
                 xmlstream.writeStartElement("p");
                 xmlstream.writeAttribute("name", property.getKey());
-                xmlstream.writeCharacters(String.valueOf(property.getValue()));
+                xmlstream.writeCharacters(safeToString(property.getValue()));
                 xmlstream.writeEndElement(); // p
             }
             xmlstream.writeEndElement(); // properties
@@ -541,6 +541,14 @@
         return nodes;
     }
 
+    private static String safeToString(Object value) {
+        try {
+            return String.valueOf(value);
+        } catch (Throwable ex) {
+            return value.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(value));
+        }
+    }
+
     public class GraphPrintAdapter {
 
         public void createElementForNode(Object node) {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeClass.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeClass.java	Fri Nov 06 20:54:49 2015 +0100
@@ -53,6 +53,8 @@
         }
     };
 
+    private static final NodeFieldAccessor[] EMPTY_NODE_FIELD_ARRAY = new NodeFieldAccessor[0];
+
     // The comprehensive list of all fields.
     private final NodeFieldAccessor[] fields;
     // Separate arrays for the frequently accessed fields.
@@ -68,11 +70,11 @@
         return nodeClasses.get(clazz);
     }
 
-    public static NodeClass get(Node clazz) {
-        return clazz.getNodeClass();
+    public static NodeClass get(Node node) {
+        return node.getNodeClass();
     }
 
-    public NodeClass(Class<? extends Node> clazz) {
+    NodeClass(Class<? extends Node> clazz) {
         List<NodeFieldAccessor> fieldsList = new ArrayList<>();
         NodeFieldAccessor parentFieldTmp = null;
         NodeFieldAccessor nodeClassFieldTmp = null;
@@ -115,12 +117,12 @@
             throw new AssertionError("parent field not found");
         }
 
-        this.fields = fieldsList.toArray(new NodeFieldAccessor[fieldsList.size()]);
+        this.fields = fieldsList.toArray(EMPTY_NODE_FIELD_ARRAY);
         this.nodeClassField = nodeClassFieldTmp;
         this.parentField = parentFieldTmp;
-        this.childFields = childFieldList.toArray(new NodeFieldAccessor[childFieldList.size()]);
-        this.childrenFields = childrenFieldList.toArray(new NodeFieldAccessor[childrenFieldList.size()]);
-        this.cloneableFields = cloneableFieldList.toArray(new NodeFieldAccessor[cloneableFieldList.size()]);
+        this.childFields = childFieldList.toArray(EMPTY_NODE_FIELD_ARRAY);
+        this.childrenFields = childrenFieldList.toArray(EMPTY_NODE_FIELD_ARRAY);
+        this.cloneableFields = cloneableFieldList.toArray(EMPTY_NODE_FIELD_ARRAY);
         this.clazz = clazz;
     }
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CyclicAssumption.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CyclicAssumption.java	Fri Nov 06 20:54:49 2015 +0100
@@ -24,10 +24,11 @@
  */
 package com.oracle.truffle.api.utilities;
 
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
 import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.Truffle;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Holds an {@link Assumption}, and knows how to recreate it with the same properties on
@@ -39,22 +40,24 @@
 public class CyclicAssumption {
 
     private final String name;
-    private final AtomicReference<Assumption> assumption;
+    private volatile Assumption assumption;
+
+    private static final AtomicReferenceFieldUpdater<CyclicAssumption, Assumption> ASSUMPTION_UPDATER = AtomicReferenceFieldUpdater.newUpdater(CyclicAssumption.class, Assumption.class, "assumption");
 
     public CyclicAssumption(String name) {
         this.name = name;
-        this.assumption = new AtomicReference<>(Truffle.getRuntime().createAssumption(name));
+        this.assumption = Truffle.getRuntime().createAssumption(name);
     }
 
     @TruffleBoundary
     public void invalidate() {
         Assumption newAssumption = Truffle.getRuntime().createAssumption(name);
-        Assumption oldAssumption = assumption.getAndSet(newAssumption);
+        Assumption oldAssumption = ASSUMPTION_UPDATER.getAndSet(this, newAssumption);
         oldAssumption.invalidate();
     }
 
     public Assumption getAssumption() {
-        return assumption.get();
+        return assumption;
     }
 
 }
--- a/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Fri Nov 06 20:54:49 2015 +0100
@@ -72,20 +72,21 @@
     }
 
     public boolean isCacheBoundByGuard(CacheExpression cacheExpression) {
+        VariableElement cachedVariable = cacheExpression.getParameter().getVariableElement();
+
         for (GuardExpression expression : getGuards()) {
-            if (expression.getExpression().findBoundVariableElements().contains(cacheExpression.getParameter().getVariableElement())) {
+            if (expression.getExpression().findBoundVariableElements().contains(cachedVariable)) {
                 return true;
             }
         }
 
-        // check all next binding caches if they are bound by guard
-        Set<VariableElement> boundVariables = cacheExpression.getExpression().findBoundVariableElements();
+        // check all next binding caches if they are bound to a guard and use this cache variable
         boolean found = false;
         for (CacheExpression expression : getCaches()) {
             if (cacheExpression == expression) {
                 found = true;
             } else if (found) {
-                if (boundVariables.contains(expression.getParameter().getVariableElement())) {
+                if (expression.getExpression().findBoundVariableElements().contains(cachedVariable)) {
                     if (isCacheBoundByGuard(expression)) {
                         return true;
                     }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Fri Nov 06 20:54:49 2015 +0100
@@ -50,6 +50,7 @@
 import java.util.List;
 
 import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.TruffleLanguage;
@@ -185,7 +186,7 @@
  */
 
 /*
- *
+ * 
  * <p> <b>Tools:</b><br> The use of some of Truffle's support for developer tools (based on the
  * Truffle {@linkplain Instrumenter Instrumentation Framework}) are demonstrated in this file, for
  * example: <ul> <li>a {@linkplain NodeExecCounter counter for node executions}, tabulated by node
@@ -419,6 +420,7 @@
             failed[0] = e;
         }
         return new CallTarget() {
+            @TruffleBoundary
             @Override
             public Object call(Object... arguments) {
                 if (failed[0] instanceof RuntimeException) {
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java	Fri Nov 06 20:54:49 2015 +0100
@@ -73,11 +73,10 @@
      * We use a separate long specialization to avoid boxing for long.
      */
     @Specialization(limit = "CACHE_LIMIT", guards = {"longLocation != null", "shape.check(receiver)"}, assumptions = "shape.getValidAssumption()")
-    @SuppressWarnings("unused")
     protected long doCachedLong(DynamicObject receiver,   //
                     @Cached("receiver.getShape()") Shape shape,   //
                     @Cached("getLongLocation(shape)") LongLocation longLocation) {
-        return longLocation.getLong(receiver, true);
+        return longLocation.getLong(receiver, shape);
     }
 
     protected LongLocation getLongLocation(Shape shape) {
@@ -108,27 +107,14 @@
      */
     @Specialization(contains = "doCachedObject")
     @TruffleBoundary
-    protected Object doGeneric(DynamicObject receiver, @Cached("new()") LRUPropertyLookup lruCache) {
-        if (!lruCache.shape.check(receiver)) {
-            Shape receiverShape = receiver.getShape();
-            lruCache.shape = receiverShape;
-            lruCache.property = receiverShape.getProperty(propertyName);
-        }
-        if (lruCache.property != null) {
-            return lruCache.property.get(receiver, true);
+    protected Object doGeneric(DynamicObject receiver) {
+        Shape shape = receiver.getShape();
+        Property property = shape.getProperty(propertyName);
+        if (property != null) {
+            return property.get(receiver, shape);
         } else {
             return SLNull.SINGLETON;
         }
     }
 
-    protected static class LRUPropertyLookup {
-
-        private Shape shape;
-        private Property property;
-
-        public LRUPropertyLookup() {
-        }
-
-    }
-
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java	Fri Nov 06 20:54:49 2015 +0100
@@ -42,9 +42,9 @@
 
 import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.InvalidAssumptionException;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.FinalLocationException;
@@ -52,8 +52,11 @@
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Property;
 import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.utilities.AlwaysValidAssumption;
+import com.oracle.truffle.api.utilities.NeverValidAssumption;
 
 public abstract class SLWritePropertyCacheNode extends Node {
+    protected static final int CACHE_LIMIT = 3;
 
     protected final String propertyName;
 
@@ -63,105 +66,78 @@
 
     public abstract void executeObject(DynamicObject receiver, Object value);
 
-    @Specialization(guards = "location.isValid(receiver, value)", assumptions = "location.getAssumptions()")
-    public void writeCached(DynamicObject receiver, Object value,   //
-                    @Cached("createCachedWrite(receiver, value)") CachedWriteLocation location) {
-        if (location.writeUnchecked(receiver, value)) {
-            // write successful
-        } else {
+    @Specialization(guards = {"location != null", "shape.check(receiver)", "canSet(location, receiver, value)"}, assumptions = {"shape.getValidAssumption()"}, limit = "CACHE_LIMIT")
+    public void writeExistingPropertyCached(DynamicObject receiver, Object value, //
+                    @Cached("lookupLocation(receiver, value)") Location location, //
+                    @Cached("receiver.getShape()") Shape shape, //
+                    @Cached("ensureValid(receiver)") Assumption validAssumption) {
+        try {
+            validAssumption.check();
+        } catch (InvalidAssumptionException e) {
             executeObject(receiver, value);
+            return;
         }
-    }
-
-    @Specialization(contains = "writeCached")
-    @TruffleBoundary
-    public void writeGeneric(DynamicObject receiver, Object value,   //
-                    @Cached("new(createCachedWrite(receiver, value))") LRUCachedWriteLocation lru) {
-        CachedWriteLocation location = lru.location;
-        if (!location.isValid(receiver, value) || !location.areAssumptionsValid()) {
-            location = createCachedWrite(receiver, value);
-            lru.location = location;
-        }
-        if (location.writeUnchecked(receiver, value)) {
-            // write successful
-        } else {
-            executeObject(receiver, value);
+        try {
+            location.set(receiver, value, shape);
+        } catch (IncompatibleLocationException | FinalLocationException e) {
+            throw new IllegalStateException(e);
         }
     }
 
-    protected CachedWriteLocation createCachedWrite(DynamicObject receiver, Object value) {
-        while (receiver.updateShape()) {
-            // multiple shape updates might be needed.
-        }
-
-        Shape oldShape = receiver.getShape();
-        Shape newShape;
-        Property property = oldShape.getProperty(propertyName);
-
-        if (property != null && property.getLocation().canSet(receiver, value)) {
-            newShape = oldShape;
-        } else {
-            receiver.define(propertyName, value, 0);
-            newShape = receiver.getShape();
-            property = newShape.getProperty(propertyName);
-        }
-
-        if (!oldShape.check(receiver)) {
-            return createCachedWrite(receiver, value);
+    @Specialization(guards = {"existing == null", "shapeBefore.check(receiver)", "canSet(newLocation, receiver, value)"}, assumptions = {"shapeBefore.getValidAssumption()",
+                    "shapeAfter.getValidAssumption()"}, limit = "CACHE_LIMIT")
+    public void writeNewPropertyCached(DynamicObject receiver, Object value, //
+                    @Cached("lookupLocation(receiver, value)") @SuppressWarnings("unused") Location existing, //
+                    @Cached("receiver.getShape()") Shape shapeBefore, //
+                    @Cached("defineProperty(receiver, value)") Shape shapeAfter, //
+                    @Cached("getLocation(shapeAfter)") Location newLocation, //
+                    @Cached("ensureValid(receiver)") Assumption validAssumption) {
+        try {
+            validAssumption.check();
+        } catch (InvalidAssumptionException e) {
+            executeObject(receiver, value);
+            return;
         }
-
-        return new CachedWriteLocation(oldShape, newShape, property.getLocation());
-
-    }
-
-    protected static final class CachedWriteLocation {
-
-        private final Shape oldShape;
-        private final Shape newShape;
-        private final Location location;
-        private final Assumption validLocation = Truffle.getRuntime().createAssumption();
-
-        public CachedWriteLocation(Shape oldShape, Shape newShape, Location location) {
-            this.oldShape = oldShape;
-            this.newShape = newShape;
-            this.location = location;
-        }
-
-        public boolean areAssumptionsValid() {
-            return validLocation.isValid() && oldShape.getValidAssumption().isValid() && newShape.getValidAssumption().isValid();
-        }
-
-        public Assumption[] getAssumptions() {
-            return new Assumption[]{oldShape.getValidAssumption(), newShape.getValidAssumption(), validLocation};
-        }
-
-        public boolean isValid(DynamicObject receiver, Object value) {
-            return oldShape.check(receiver) && location.canSet(receiver, value);
-        }
-
-        public boolean writeUnchecked(DynamicObject receiver, Object value) {
-            try {
-                if (oldShape == newShape) {
-                    location.set(receiver, value, oldShape);
-                } else {
-                    location.set(receiver, value, oldShape, newShape);
-                }
-                return true;
-            } catch (IncompatibleLocationException | FinalLocationException e) {
-                validLocation.invalidate();
-                return false;
-            }
+        try {
+            newLocation.set(receiver, value, shapeBefore, shapeAfter);
+        } catch (IncompatibleLocationException e) {
+            throw new IllegalStateException(e);
         }
     }
 
-    protected static final class LRUCachedWriteLocation {
+    @Specialization(contains = {"writeExistingPropertyCached", "writeNewPropertyCached"})
+    @TruffleBoundary
+    public void writeUncached(DynamicObject receiver, Object value) {
+        receiver.define(propertyName, value);
+    }
 
-        private CachedWriteLocation location;
+    protected final Location lookupLocation(DynamicObject object, Object value) {
+        final Shape oldShape = object.getShape();
+        final Property property = oldShape.getProperty(propertyName);
+
+        if (property != null && property.getLocation().canSet(object, value)) {
+            return property.getLocation();
+        } else {
+            return null;
+        }
+    }
 
-        public LRUCachedWriteLocation(CachedWriteLocation location) {
-            this.location = location;
-        }
+    protected final Shape defineProperty(DynamicObject receiver, Object value) {
+        Shape oldShape = receiver.getShape();
+        Shape newShape = oldShape.defineProperty(propertyName, value, 0);
+        return newShape;
+    }
 
+    protected final Location getLocation(Shape newShape) {
+        return newShape.getProperty(propertyName).getLocation();
+    }
+
+    protected static Assumption ensureValid(DynamicObject receiver) {
+        return receiver.updateShape() ? NeverValidAssumption.INSTANCE : AlwaysValidAssumption.INSTANCE;
+    }
+
+    protected static boolean canSet(Location location, DynamicObject receiver, Object value) {
+        return location.canSet(receiver, value);
     }
 
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Fri Nov 06 20:54:49 2015 +0100
@@ -43,7 +43,6 @@
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.EventHandlerNode;
 import com.oracle.truffle.api.instrument.Instrumenter;
-import com.oracle.truffle.api.instrument.KillException;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.WrapperNode;
@@ -107,8 +106,6 @@
         try {
             result = child.executeGeneric(vFrame);
             eventHandlerNode.returnValue(child, vFrame, result);
-        } catch (KillException e) {
-            throw (e);
         } catch (Exception e) {
             eventHandlerNode.returnExceptional(child, vFrame, e);
             throw (e);
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Fri Nov 06 20:54:49 2015 +0100
@@ -43,7 +43,6 @@
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.EventHandlerNode;
 import com.oracle.truffle.api.instrument.Instrumenter;
-import com.oracle.truffle.api.instrument.KillException;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.WrapperNode;
@@ -100,8 +99,6 @@
         try {
             child.executeVoid(vFrame);
             eventHandlerNode.returnVoid(child, vFrame);
-        } catch (KillException e) {
-            throw (e);
         } catch (Exception e) {
             eventHandlerNode.returnExceptional(child, vFrame, e);
             throw (e);
--- a/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/ToolTestUtil.java	Wed Nov 04 16:54:36 2015 +0100
+++ b/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/ToolTestUtil.java	Fri Nov 06 20:54:49 2015 +0100
@@ -35,7 +35,6 @@
 import com.oracle.truffle.api.instrument.ASTProber;
 import com.oracle.truffle.api.instrument.EventHandlerNode;
 import com.oracle.truffle.api.instrument.Instrumenter;
-import com.oracle.truffle.api.instrument.KillException;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.SyntaxTag;
 import com.oracle.truffle.api.instrument.Visualizer;
@@ -212,8 +211,6 @@
             try {
                 result = child.execute(vFrame);
                 eventHandlerNode.returnValue(child, vFrame, result);
-            } catch (KillException e) {
-                throw (e);
             } catch (Exception e) {
                 eventHandlerNode.returnExceptional(child, vFrame, e);
                 throw (e);