changeset 18641:e22a21b27036

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 07 Dec 2014 20:43:33 +0100
parents 02b5114b74c1 (current diff) 56f806632622 (diff)
children 133d5a98c547
files
diffstat 34 files changed, 990 insertions(+), 250 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Sun Dec 07 20:43:33 2014 +0100
@@ -25,12 +25,16 @@
 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.meta.*;
 
-public interface ReferenceMap {
+public interface ReferenceMap extends Cloneable {
 
     void setRegister(int idx, LIRKind kind);
 
+    void clearRegister(int idx, LIRKind kind);
+
     void setStackSlot(int offset, LIRKind kind);
 
+    void clearStackSlot(int offset, LIRKind kind);
+
     boolean hasRegisterRefMap();
 
     boolean hasFrameRefMap();
@@ -38,4 +42,11 @@
     void appendRegisterMap(StringBuilder sb, RefMapFormatter formatterArg);
 
     void appendFrameMap(StringBuilder sb, RefMapFormatter formatterArg);
+
+    ReferenceMap clone();
+
+    /**
+     * Updates this map with all references marked in {@code other}.
+     */
+    void updateUnion(ReferenceMap other);
 }
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Sun Dec 07 20:43:33 2014 +0100
@@ -158,13 +158,27 @@
                 }
 
                 try (Scope s = Debug.scope("Allocator")) {
-
                     if (backend.shouldAllocateRegisters()) {
                         LinearScan.allocate(target, lirGenRes);
+                    } else if (!LocationMarker.Options.UseLocationMarker.getValue()) {
+                        // build frame map for targets that do not allocate registers
+                        lirGenRes.buildFrameMap();
                     }
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
                 }
+                if (LocationMarker.Options.UseLocationMarker.getValue()) {
+                    try (Scope s1 = Debug.scope("BuildFrameMap")) {
+                        // build frame map
+                        lirGenRes.buildFrameMap();
+                        Debug.dump(lir, "After FrameMap building");
+                    }
+                    try (Scope s1 = Debug.scope("MarkLocations")) {
+                        if (backend.shouldAllocateRegisters()) {
+                            // currently we mark locations only if we do register allocation
+                            LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
+                        }
+                    }
+                }
+
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sun Dec 07 20:43:33 2014 +0100
@@ -351,7 +351,7 @@
             try (Scope s = Debug.scope("Allocator", nodeLirGen)) {
                 if (backend.shouldAllocateRegisters()) {
                     LinearScan.allocate(target, lirGenRes);
-                } else {
+                } else if (!LocationMarker.Options.UseLocationMarker.getValue()) {
                     // build frame map for targets that do not allocate registers
                     lirGenRes.buildFrameMap();
                 }
@@ -359,6 +359,20 @@
                 throw Debug.handle(e);
             }
 
+            if (LocationMarker.Options.UseLocationMarker.getValue()) {
+                try (Scope s1 = Debug.scope("BuildFrameMap")) {
+                    // build frame map
+                    lirGenRes.buildFrameMap();
+                    Debug.dump(lir, "After FrameMap building");
+                }
+                try (Scope s1 = Debug.scope("MarkLocations")) {
+                    if (backend.shouldAllocateRegisters()) {
+                        // currently we mark locations only if we do register allocation
+                        LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
+                    }
+                }
+            }
+
             try (Scope s = Debug.scope("ControlFlowOptimizations")) {
                 EdgeMoveOptimizer.optimize(lir);
                 ControlFlowOptimizer.optimize(lir, codeEmittingOrder);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Sun Dec 07 20:43:33 2014 +0100
@@ -1713,6 +1713,9 @@
      * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
      */
     private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
+        if (isVirtualStackSlot(operand)) {
+            return operand;
+        }
         int tempOpId = op.id();
         OperandMode mode = OperandMode.USE;
         AbstractBlock<?> block = blockForId(tempOpId);
@@ -1742,12 +1745,16 @@
     }
 
     private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
-        FrameMap frameMap = res.getFrameMap();
-        info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters);
-        markFrameLocations(iw, op, info, frameMap);
+        if (!LocationMarker.Options.UseLocationMarker.getValue()) {
+            FrameMap frameMap = res.getFrameMap();
+            info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters);
+            markFrameLocations(iw, op, info, frameMap);
+        }
 
         info.forEachState(op, this::debugInfoProcedure);
-        info.finish(op, frameMap);
+        if (!LocationMarker.Options.UseLocationMarker.getValue()) {
+            info.finish(op, res.getFrameMap());
+        }
     }
 
     private void assignLocations(List<LIRInstruction> instructions, final IntervalWalker iw) {
@@ -1887,8 +1894,11 @@
 
                 // register interval mapper
                 frameMapBuilder.requireMapping(new Mapper());
-                // build frame map
-                res.buildFrameMap();
+
+                if (!LocationMarker.Options.UseLocationMarker.getValue()) {
+                    // build frame map
+                    res.buildFrameMap();
+                }
 
                 printLir("After FrameMap building", true);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LocationMarker.java	Sun Dec 07 20:43:33 2014 +0100
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2014, 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.graal.compiler.alloc;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.options.*;
+
+public final class LocationMarker {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use decoupled pass for location marking (instead of using LSRA marking)")
+        public static final OptionValue<Boolean> UseLocationMarker = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    /**
+     * Mark all live references for a frame state. The frame state use this information to build the
+     * OOP maps.
+     */
+    public static void markLocations(LIR lir, FrameMap frameMap) {
+        new LocationMarker(lir, frameMap).build();
+    }
+
+    private final LIR lir;
+    private final FrameMap frameMap;
+    private final RegisterAttributes[] registerAttributes;
+    private final BlockMap<ReferenceMap> liveInMap;
+    private final BlockMap<ReferenceMap> liveOutMap;
+
+    private LocationMarker(LIR lir, FrameMap frameMap) {
+        this.lir = lir;
+        this.frameMap = frameMap;
+        this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
+        liveInMap = new BlockMap<>(lir.getControlFlowGraph());
+        liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+    }
+
+    private void build() {
+        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+        for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
+            worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
+        }
+        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+            liveInMap.put(block, frameMap.initReferenceMap(true));
+        }
+        while (!worklist.isEmpty()) {
+            AbstractBlock<?> block = worklist.poll();
+            processBlock(block, worklist);
+        }
+        // finish states
+        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            for (int i = instructions.size() - 1; i >= 0; i--) {
+                LIRInstruction inst = instructions.get(i);
+                inst.forEachState((op, info) -> info.finish(op, frameMap));
+            }
+
+        }
+    }
+
+    /**
+     * Merge outSet with in-set of successors.
+     */
+    private boolean updateOutBlock(AbstractBlock<?> block) {
+        ReferenceMap union = frameMap.initReferenceMap(true);
+        block.getSuccessors().forEach(succ -> union.updateUnion(liveInMap.get(succ)));
+        ReferenceMap outSet = liveOutMap.get(block);
+        // check if changed
+        if (outSet == null || !union.equals(outSet)) {
+            liveOutMap.put(block, union);
+            return true;
+        }
+        return false;
+    }
+
+    private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
+        if (updateOutBlock(block)) {
+            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                for (int i = instructions.size() - 1; i >= 0; i--) {
+                    LIRInstruction inst = instructions.get(i);
+                    closure.processInstructionBottomUp(inst);
+                }
+                liveInMap.put(block, closure.getCurrentSet());
+                worklist.addAll(block.getPredecessors());
+            }
+        }
+    }
+
+    private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
+    private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
+
+    private void forEachDestroyedCallerSavedRegister(LIRInstruction op, ValueConsumer consumer) {
+        if (op.destroysCallerSavedRegisters()) {
+            for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
+                consumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
+            }
+        }
+    }
+
+    private final class BlockClosure {
+        private final ReferenceMap currentSet;
+
+        private BlockClosure(ReferenceMap set) {
+            currentSet = set;
+        }
+
+        private ReferenceMap getCurrentSet() {
+            return currentSet;
+        }
+
+        /**
+         * Process all values of an instruction bottom-up, i.e. definitions before usages. Values
+         * that start or end at the current operation are not included.
+         */
+        private void processInstructionBottomUp(LIRInstruction op) {
+            try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
+                // kills
+                op.visitEachTemp(this::defConsumer);
+                op.visitEachOutput(this::defConsumer);
+                forEachDestroyedCallerSavedRegister(op, this::defConsumer);
+
+                // gen - values that are considered alive for this state
+                op.visitEachAlive(this::useConsumer);
+                op.visitEachState(this::useConsumer);
+                // mark locations
+                op.forEachState((inst, info) -> markLocation(inst, info, this.getCurrentSet()));
+                // gen
+                op.visitEachInput(this::useConsumer);
+            }
+        }
+
+        /**
+         * @see InstructionValueConsumer
+         * @param operand
+         * @param mode
+         * @param flags
+         */
+        private void useConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            LIRKind kind = operand.getLIRKind();
+            if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) {
+                // no need to insert values and derived reference
+                Debug.log("set operand: %s", operand);
+                frameMap.setReference(operand, currentSet);
+            }
+        }
+
+        /**
+         * @see InstructionValueConsumer
+         * @param operand
+         * @param mode
+         * @param flags
+         */
+        private void defConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (shouldProcessValue(operand)) {
+                Debug.log("clear operand: %s", operand);
+                frameMap.clearReference(operand, currentSet);
+            }
+        }
+
+        protected boolean shouldProcessValue(Value operand) {
+            return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getKind() != Kind.Illegal;
+        }
+    }
+
+    /**
+     * This method does the actual marking.
+     */
+    private void markLocation(LIRInstruction op, LIRFrameState info, ReferenceMap refMap) {
+        if (!info.hasDebugInfo()) {
+            info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
+        }
+        info.updateUnion(refMap);
+    }
+
+    /**
+     * Gets an object describing the attributes of a given register according to this register
+     * configuration.
+     *
+     * @see LinearScan#attributes
+     */
+    private RegisterAttributes attributes(Register reg) {
+        return registerAttributes[reg.number];
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Sun Dec 07 20:43:33 2014 +0100
@@ -26,6 +26,7 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import java.util.*;
+import java.util.concurrent.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
@@ -51,7 +52,7 @@
 
     private final boolean allAllocatableAreCallerSaved;
 
-    private final HashMap<PlatformKind, Register[]> categorized = new HashMap<>();
+    private final Map<PlatformKind, Register[]> categorized = new ConcurrentHashMap<>();
 
     private final RegisterAttributes[] attributesMap;
 
--- a/graal/com.oracle.graal.hotspot.loader/src/com/oracle/graal/hotspot/loader/Factory.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.loader/src/com/oracle/graal/hotspot/loader/Factory.java	Sun Dec 07 20:43:33 2014 +0100
@@ -26,19 +26,31 @@
 import java.net.*;
 
 /**
- * Utility to create a separate class loader for loading classes in {@code graal.jar} and
- * {@code graal-truffle.jar}.
+ * Utility to create and register a separate class loader for loading Graal classes (i.e., those in
+ * {@code graal.jar} and {@code graal-truffle.jar}).
  */
 public class Factory {
 
     /**
+     * Copy of the {@code UseGraalClassLoader} VM option. Set by the VM before the static
+     * initializer is called.
+     */
+    private static boolean useGraalClassLoader;
+
+    /**
+     * Registers the Graal class loader in the VM.
+     */
+    private static native void init(ClassLoader loader);
+
+    static {
+        init(useGraalClassLoader ? newClassLoader() : null);
+    }
+
+    /**
      * Creates a new class loader for loading classes in {@code graal.jar} and
-     * {@code graal-truffle.jar}
-     *
-     * Called from the VM.
+     * {@code graal-truffle.jar}.
      */
-    @SuppressWarnings("unused")
-    private static ClassLoader newClassLoader() throws MalformedURLException {
+    private static ClassLoader newClassLoader() {
         URL[] urls = {getGraalJarUrl("graal"), getGraalJarUrl("graal-truffle")};
         ClassLoader parent = null;
         return URLClassLoader.newInstance(urls, parent);
@@ -47,7 +59,7 @@
     /**
      * Gets the URL for {@code base.jar}.
      */
-    private static URL getGraalJarUrl(String base) throws MalformedURLException {
+    private static URL getGraalJarUrl(String base) {
         File file = new File(System.getProperty("java.home"));
         for (String name : new String[]{"lib", base + ".jar"}) {
             file = new File(file, name);
@@ -57,6 +69,10 @@
             throw new InternalError(file + " does not exist");
         }
 
-        return file.toURI().toURL();
+        try {
+            return file.toURI().toURL();
+        } catch (MalformedURLException e) {
+            throw new InternalError(e);
+        }
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Sun Dec 07 20:43:33 2014 +0100
@@ -26,6 +26,7 @@
 import static com.oracle.graal.sparc.SPARC.*;
 
 import java.util.*;
+import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
@@ -42,7 +43,7 @@
 
     private final Register[] allocatable;
 
-    private final HashMap<PlatformKind, Register[]> categorized = new HashMap<>();
+    private final Map<PlatformKind, Register[]> categorized = new ConcurrentHashMap<>(20);
 
     private final RegisterAttributes[] attributesMap;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Sun Dec 07 20:43:33 2014 +0100
@@ -79,6 +79,19 @@
         this.target = target;
     }
 
+    private HotSpotReferenceMap(HotSpotReferenceMap other) {
+        this.registerRefMap = (BitSet) other.registerRefMap.clone();
+        this.frameRefMap = (BitSet) other.frameRefMap.clone();
+        this.target = other.target;
+    }
+
+    @Override
+    public ReferenceMap clone() {
+        return new HotSpotReferenceMap(this);
+    }
+
+    // setters
+
     private static void setOop(BitSet map, int startIdx, LIRKind kind) {
         int length = kind.getPlatformKind().getVectorLength();
         map.clear(BITS_PER_WORD * startIdx, BITS_PER_WORD * (startIdx + length) - 1);
@@ -154,6 +167,194 @@
         }
     }
 
+    // clear
+
+    private static void clearOop(BitSet map, int startIdx, LIRKind kind) {
+        int length = kind.getPlatformKind().getVectorLength();
+        map.clear(BITS_PER_WORD * startIdx, BITS_PER_WORD * (startIdx + length) - 1);
+    }
+
+    private static void clearNarrowOop(BitSet map, int idx, LIRKind kind) {
+        int length = kind.getPlatformKind().getVectorLength();
+        int nextIdx = idx + (length + 1) / 2;
+        map.clear(BITS_PER_WORD * idx, BITS_PER_WORD * nextIdx - 1);
+    }
+
+    public void clearRegister(int idx, LIRKind kind) {
+
+        PlatformKind platformKind = kind.getPlatformKind();
+        int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
+
+        if (bytesPerElement == target.wordSize) {
+            clearOop(registerRefMap, idx, kind);
+        } else if (bytesPerElement == target.wordSize / 2) {
+            clearNarrowOop(registerRefMap, idx, kind);
+        } else {
+            assert kind.isValue() : "unsupported reference kind " + kind;
+        }
+    }
+
+    public void clearStackSlot(int offset, LIRKind kind) {
+
+        PlatformKind platformKind = kind.getPlatformKind();
+        int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
+        assert offset % bytesPerElement == 0 : "unaligned value in ReferenceMap";
+
+        if (bytesPerElement == target.wordSize) {
+            clearOop(frameRefMap, offset / target.wordSize, kind);
+        } else if (bytesPerElement == target.wordSize / 2) {
+            if (platformKind.getVectorLength() > 1) {
+                clearNarrowOop(frameRefMap, offset / target.wordSize, kind);
+            } else {
+                // in this case, offset / target.wordSize may not divide evenly
+                // so setNarrowOop won't work correctly
+                int idx = offset / target.wordSize;
+                if (kind.isReference(0)) {
+                    if (offset % target.wordSize == 0) {
+                        frameRefMap.clear(BITS_PER_WORD * idx + 1);
+                        if (!frameRefMap.get(BITS_PER_WORD * idx + 2)) {
+                            // only reset the first bit if there is no other narrow oop
+                            frameRefMap.clear(BITS_PER_WORD * idx);
+                        }
+                    } else {
+                        frameRefMap.clear(BITS_PER_WORD * idx + 2);
+                        if (!frameRefMap.get(BITS_PER_WORD * idx + 1)) {
+                            // only reset the first bit if there is no other narrow oop
+                            frameRefMap.clear(BITS_PER_WORD * idx);
+                        }
+                    }
+                }
+            }
+        } else {
+            assert kind.isValue() : "unknown reference kind " + kind;
+        }
+    }
+
+    public void updateUnion(ReferenceMap otherArg) {
+        HotSpotReferenceMap other = (HotSpotReferenceMap) otherArg;
+        if (registerRefMap != null) {
+            assert other.registerRefMap != null;
+            updateUnionBitSetRaw(registerRefMap, other.registerRefMap);
+        } else {
+            assert other.registerRefMap == null || other.registerRefMap.cardinality() == 0 : "Target register reference map is empty but the source is not: " + other.registerRefMap;
+        }
+        updateUnionBitSetRaw(frameRefMap, other.frameRefMap);
+    }
+
+    /**
+     * Update {@code src} with the union of {@code src} and {@code dst}.
+     *
+     * @see HotSpotReferenceMap#registerRefMap
+     * @see HotSpotReferenceMap#frameRefMap
+     */
+    private static void updateUnionBitSetRaw(BitSet dst, BitSet src) {
+        assert dst.size() == src.size();
+        assert UpdateUnionVerifier.verifyUpate(dst, src);
+        dst.or(src);
+    }
+
+    private enum UpdateUnionVerifier {
+        NoReference,
+        WideOop,
+        NarrowOopLowerHalf,
+        NarrowOopUpperHalf,
+        TwoNarrowOops,
+        Illegal;
+
+        /**
+         * Create enum values from BitSet.
+         * <p>
+         * These bits can have the following values (LSB first):
+         *
+         * <pre>
+         * 000 - contains no references
+         * 100 - contains a wide oop
+         * 110 - contains a narrow oop in the lower half
+         * 101 - contains a narrow oop in the upper half
+         * 111 - contains two narrow oops
+         * </pre>
+         *
+         * @see HotSpotReferenceMap#registerRefMap
+         * @see HotSpotReferenceMap#frameRefMap
+         */
+        static UpdateUnionVerifier getFromBits(int idx, BitSet set) {
+            int n = (set.get(idx) ? 1 : 0) << 0 | (set.get(idx + 1) ? 1 : 0) << 1 | (set.get(idx + 2) ? 1 : 0) << 2;
+            switch (n) {
+                case 0:
+                    return NoReference;
+                case 1:
+                    return WideOop;
+                case 3:
+                    return NarrowOopLowerHalf;
+                case 5:
+                    return NarrowOopUpperHalf;
+                case 7:
+                    return TwoNarrowOops;
+                default:
+                    return Illegal;
+            }
+        }
+
+        String toBitString() {
+            int bits = toBit(this);
+            if (bits == -1) {
+                return "---";
+            }
+            return String.format("%3s", Integer.toBinaryString(bits)).replace(' ', '0');
+        }
+
+        static int toBit(UpdateUnionVerifier type) {
+            switch (type) {
+                case NoReference:
+                    return 0;
+                case WideOop:
+                    return 1;
+                case NarrowOopLowerHalf:
+                    return 3;
+                case NarrowOopUpperHalf:
+                    return 5;
+                case TwoNarrowOops:
+                    return 7;
+                default:
+                    return -1;
+            }
+        }
+
+        private static boolean verifyUpate(BitSet dst, BitSet src) {
+            for (int idx = 0; idx < dst.size(); idx += BITS_PER_WORD) {
+                if (!verifyUpdateEntry(idx, dst, src)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private static boolean verifyUpdateEntry(int idx, BitSet dst, BitSet src) {
+            UpdateUnionVerifier dstType = UpdateUnionVerifier.getFromBits(idx, dst);
+            UpdateUnionVerifier srcType = UpdateUnionVerifier.getFromBits(idx, src);
+
+            if (dstType == UpdateUnionVerifier.Illegal || srcType == UpdateUnionVerifier.Illegal) {
+                assert false : String.format("Illegal RefMap bit pattern: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
+                return false;
+            }
+            switch (dstType) {
+                case NoReference:
+                    return true;
+                case WideOop:
+                    switch (srcType) {
+                        case NoReference:
+                        case WideOop:
+                            return true;
+                        default:
+                            assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
+                            return false;
+                    }
+                default:
+                    return true;
+            }
+        }
+    }
+
     @Override
     public int hashCode() {
         throw new UnsupportedOperationException();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Sun Dec 07 20:43:33 2014 +0100
@@ -191,7 +191,8 @@
         Object nonNullDest = guardingNonNull(dest);
         checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length);
         if (probability(SLOW_PATH_PROBABILITY, nonNullSrc == nonNullDest)) {
-            System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
+            // no storecheck required.
+            ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, Kind.Object, false, false);
         } else {
             KlassPointer destElemKlass = loadHub(nonNullDest);
             checkcastArraycopyHelper(srcPos, destPos, length, nonNullSrc, nonNullDest, destElemKlass);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Sun Dec 07 20:43:33 2014 +0100
@@ -134,6 +134,13 @@
     }
 
     /**
+     * Updates this reference map with all references that are marked in {@code refMap}.
+     */
+    public void updateUnion(ReferenceMap refMap) {
+        debugInfo.getReferenceMap().updateUnion(refMap);
+    }
+
+    /**
      * Called by the register allocator after all locations are marked.
      *
      * @param op The instruction to which this frame state belongs.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java	Sun Dec 07 20:43:33 2014 +0100
@@ -337,4 +337,16 @@
             assert isConstant(location);
         }
     }
+
+    public void clearReference(Value location, ReferenceMap refMap) {
+        LIRKind kind = location.getLIRKind();
+        if (isRegister(location)) {
+            refMap.clearRegister(asRegister(location).getReferenceMapIndex(), kind);
+        } else if (isStackSlot(location)) {
+            int offset = offsetForStackSlot(asStackSlot(location));
+            refMap.clearStackSlot(offset, kind);
+        } else {
+            assert isConstant(location);
+        }
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sun Dec 07 20:43:33 2014 +0100
@@ -315,10 +315,10 @@
             try {
                 Object[] args = new Object[constructor.getParameterCount()];
                 for (int i = 0; i < args.length; i++) {
-                    Object arg = snippetReflection.getSubstitutionGuardParameter(paramTypes[0]);
+                    Object arg = snippetReflection.getSubstitutionGuardParameter(paramTypes[i]);
                     if (arg != null) {
                         args[i] = arg;
-                    } else if (paramTypes[0].isInstance(target.arch)) {
+                    } else if (paramTypes[i].isInstance(target.arch)) {
                         args[i] = target.arch;
                     } else {
                         throw new GraalInternalError("Unsupported type %s in substitution guard constructor: %s", paramTypes[i].getName(), constructor);
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARCScratchRegister.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARCScratchRegister.java	Sun Dec 07 20:43:33 2014 +0100
@@ -30,6 +30,7 @@
     private final Register register;
     private static final SPARCScratchRegister scratch1 = new SPARCScratchRegister(SPARC.g3);
     private static final SPARCScratchRegister scratch2 = new SPARCScratchRegister(SPARC.g1);
+    private static final boolean LOG_REQUEST_STACK = false;
 
     private SPARCScratchRegister(Register register) {
         super();
@@ -42,10 +43,14 @@
         }
         boolean isLocked = locked.get();
         if (isLocked) {
-            where.get().printStackTrace();
+            if (LOG_REQUEST_STACK) {
+                where.get().printStackTrace();
+            }
             throw new RuntimeException("Temp Register is already taken!");
         } else {
-            where.set(new Exception());
+            if (LOG_REQUEST_STACK) {
+                where.set(new Exception());
+            }
             locked.set(true);
             return register;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java	Sun Dec 07 20:43:33 2014 +0100
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 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.api.dsl.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.ArrayTestFactory.TestNode1Factory;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+public class ArrayTest {
+
+    @Test
+    public void testNode1() {
+        final TestNode1 node = TestNode1Factory.create(null);
+        RootNode root = new RootNode() {
+            @Child TestNode1 test = node;
+
+            @Override
+            public Object execute(VirtualFrame frame) {
+                return test.executeWith(frame, frame.getArguments()[0]);
+            }
+        };
+        CallTarget target = Truffle.getRuntime().createCallTarget(root);
+
+        Assert.assertEquals(1, (int) target.call(1));
+        Assert.assertArrayEquals(new double[0], (double[]) target.call(new int[0]), 0.0d);
+        Assert.assertArrayEquals(new double[0], (double[]) target.call(new double[0]), 0.0d);
+        Assert.assertArrayEquals(new String[0], (String[]) target.call((Object) new String[0]));
+    }
+
+    @TypeSystemReference(ArrayTypeSystem.class)
+    abstract static class BaseNode extends Node {
+
+        abstract Object execute(VirtualFrame frame);
+
+        int executeInt(VirtualFrame frame) throws UnexpectedResultException {
+            return ArrayTypeSystemGen.ARRAYTYPESYSTEM.expectInteger(execute(frame));
+        }
+
+        int[] executeIntArray(VirtualFrame frame) throws UnexpectedResultException {
+            return ArrayTypeSystemGen.ARRAYTYPESYSTEM.expectIntArray(execute(frame));
+        }
+
+        String[] executeStringArray(VirtualFrame frame) throws UnexpectedResultException {
+            return ArrayTypeSystemGen.ARRAYTYPESYSTEM.expectStringArray(execute(frame));
+        }
+
+        double[] executeDoubleArray(VirtualFrame frame) throws UnexpectedResultException {
+            return ArrayTypeSystemGen.ARRAYTYPESYSTEM.expectDoubleArray(execute(frame));
+        }
+    }
+
+    @NodeChild
+    abstract static class TestNode1 extends BaseNode {
+
+        abstract Object executeWith(VirtualFrame frame, Object operand);
+
+        @Specialization
+        int doInt(int value) {
+            return value;
+        }
+
+        @Specialization
+        double[] doDoubleArray(double[] value) {
+            return value;
+        }
+
+        @Specialization
+        String[] doStringArray(String[] value) {
+            return value;
+        }
+
+    }
+
+    @TypeSystem({int.class, int[].class, double[].class, String[].class, Object[].class})
+    public static class ArrayTypeSystem {
+
+        @ImplicitCast
+        public double[] castFromInt(int[] array) {
+            double[] newArray = new double[array.length];
+            for (int i = 0; i < array.length; i++) {
+                newArray[i] = array[i];
+            }
+            return newArray;
+        }
+
+        @TypeCheck
+        public boolean isIntArray(Object array) {
+            return array instanceof int[];
+        }
+
+        @TypeCast
+        public int[] asIntArray(Object array) {
+            return (int[]) array;
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Sun Dec 07 20:43:33 2014 +0100
@@ -322,12 +322,12 @@
     /**
      * <pre>
      * variant1 $condition != null
-     * 
+     *
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     * 
+     *
      * variant2 $condition != null
      * $type $name = $value;
      * </pre>
@@ -1993,7 +1993,7 @@
             }
             String prefix = expect ? "expect" : "execute";
             String suffix = execution.getIndex() > -1 ? String.valueOf(execution.getIndex()) : "";
-            return prefix + ElementUtils.firstLetterUpperCase(child.getName()) + ElementUtils.firstLetterUpperCase(ElementUtils.getSimpleName(param.getType())) + suffix;
+            return prefix + ElementUtils.firstLetterUpperCase(child.getName()) + ElementUtils.firstLetterUpperCase(ElementUtils.getTypeId(param.getType())) + suffix;
         }
 
         private List<CodeExecutableElement> createExecuteChilds(Parameter param, Set<TypeData> expectTypes) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Sun Dec 07 20:43:33 2014 +0100
@@ -672,10 +672,6 @@
     }
 
     public CodeTreeBuilder instanceOf(String var, TypeMirror type) {
-        TypeElement element = ElementUtils.fromTypeMirror(type);
-        if (element == null) {
-            throw new IllegalArgumentException("Cannot call instanceof for a non supported type: " + type.getKind());
-        }
         return instanceOf(singleString(var), singleType(type));
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Sun Dec 07 20:43:33 2014 +0100
@@ -139,7 +139,7 @@
 
     public TypeData findType(String simpleName) {
         for (TypeData type : types) {
-            if (ElementUtils.getSimpleName(type.getBoxedType()).equals(simpleName)) {
+            if (ElementUtils.getTypeId(type.getBoxedType()).equals(simpleName)) {
                 return type;
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Sun Dec 07 20:43:33 2014 +0100
@@ -216,7 +216,11 @@
                 typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)),
                                 ElementUtils.getQualifiedName(type));
             }
-            List<String> nextInvalidTypes = ElementUtils.getQualifiedSuperTypeNames(ElementUtils.fromTypeMirror(type));
+            TypeElement element = ElementUtils.fromTypeMirror(type);
+            List<String> nextInvalidTypes = new ArrayList<>();
+            if (element != null) {
+                nextInvalidTypes.addAll(ElementUtils.getQualifiedSuperTypeNames(element));
+            }
             nextInvalidTypes.add(getQualifiedName(type));
 
             for (String qualifiedName : nextInvalidTypes) {
--- a/graal/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/ShapeBasic.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/ShapeBasic.java	Sun Dec 07 20:43:33 2014 +0100
@@ -30,13 +30,13 @@
         super(layout, operations, sharedData, id);
     }
 
-    public ShapeBasic(Layout layout, Object sharedData, ShapeImpl parent, ObjectType operations, PropertyMap propertyMap, Allocator allocator, int id) {
-        super(layout, parent, operations, sharedData, propertyMap, allocator, id);
+    public ShapeBasic(Layout layout, Object sharedData, ShapeImpl parent, ObjectType objectType, PropertyMap propertyMap, Transition transition, Allocator allocator, int id) {
+        super(layout, parent, objectType, sharedData, propertyMap, transition, allocator, id);
     }
 
     @SuppressWarnings("hiding")
     @Override
-    protected ShapeImpl createShape(Layout layout, Object sharedData, ShapeImpl parent, ObjectType operations, PropertyMap propertyMap, Allocator allocator, int id) {
-        return new ShapeBasic(layout, sharedData, parent, operations, propertyMap, allocator, id);
+    protected ShapeImpl createShape(Layout layout, Object sharedData, ShapeImpl parent, ObjectType objectType, PropertyMap propertyMap, Transition transition, Allocator allocator, int id) {
+        return new ShapeBasic(layout, sharedData, parent, objectType, propertyMap, transition, allocator, id);
     }
 }
--- a/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java	Sun Dec 07 20:43:33 2014 +0100
@@ -29,16 +29,18 @@
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.object.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.object.LocationImpl.InternalLongLocation;
 import com.oracle.truffle.object.Locations.ConstantLocation;
 import com.oracle.truffle.object.Locations.DeclaredDualLocation;
 import com.oracle.truffle.object.Locations.DeclaredLocation;
 import com.oracle.truffle.object.Locations.DualLocation;
 import com.oracle.truffle.object.Locations.ValueLocation;
-import com.oracle.truffle.object.Transition.AddTransition;
-import com.oracle.truffle.object.Transition.OperationsTransition;
+import com.oracle.truffle.object.Transition.AddPropertyTransition;
+import com.oracle.truffle.object.Transition.ObjectTypeTransition;
 import com.oracle.truffle.object.Transition.PropertyTransition;
-import com.oracle.truffle.object.Transition.RemoveTransition;
+import com.oracle.truffle.object.Transition.RemovePropertyTransition;
+import com.oracle.truffle.object.Transition.ReservePrimitiveArrayTransition;
 
 /**
  * Shape objects create a mapping of Property objects to indexes. The mapping of those indexes to an
@@ -77,7 +79,7 @@
     protected Property[] propertyArray;
 
     protected final Assumption validAssumption;
-    protected final Assumption leafAssumption;
+    @CompilationFinal protected volatile Assumption leafAssumption;
 
     /**
      * Shape transition map; lazily initialized.
@@ -87,18 +89,24 @@
      */
     private HashMap<Transition, ShapeImpl> transitionMap;
 
+    private final Transition transitionFromParent;
+
     /**
      * Private constructor.
      *
-     * @see #ShapeImpl(Layout, ShapeImpl, ObjectType, Object, PropertyMap, BaseAllocator, int)
+     * @param parent predecessor shape
+     * @param transitionFromParent direct transition from parent shape
+     * @see #ShapeImpl(Layout, ShapeImpl, ObjectType, Object, PropertyMap, Transition,
+     *      BaseAllocator, int)
      */
-    private ShapeImpl(Layout layout, ShapeImpl parent, ObjectType operations, Object sharedData, PropertyMap propertyMap, int objectArraySize, int objectFieldSize, int primitiveFieldSize,
-                    int primitiveArraySize, boolean hasPrimitiveArray, int id) {
+    private ShapeImpl(Layout layout, ShapeImpl parent, ObjectType objectType, Object sharedData, PropertyMap propertyMap, Transition transitionFromParent, int objectArraySize, int objectFieldSize,
+                    int primitiveFieldSize, int primitiveArraySize, boolean hasPrimitiveArray, int id) {
         this.layout = (LayoutImpl) layout;
-        this.objectType = Objects.requireNonNull(operations);
+        this.objectType = Objects.requireNonNull(objectType);
         this.propertyMap = Objects.requireNonNull(propertyMap);
         this.root = parent != null ? parent.getRoot() : this;
         this.parent = parent;
+        this.transitionFromParent = transitionFromParent;
         this.objectArraySize = objectArraySize;
         this.objectArrayCapacity = capacityFromSize(objectArraySize);
         this.objectFieldSize = objectFieldSize;
@@ -118,27 +126,26 @@
         }
 
         this.validAssumption = createValidAssumption();
-        this.leafAssumption = createLeafAssumption();
 
         this.id = id;
         shapeCount.inc();
 
         this.sharedData = sharedData;
-        this.extraData = operations.createShapeData(this);
+        this.extraData = objectType.createShapeData(this);
 
         debugRegisterShape(this);
     }
 
-    protected ShapeImpl(Layout layout, ShapeImpl parent, ObjectType operations, Object sharedData, PropertyMap propertyMap, Allocator allocator, int id) {
-        this(layout, parent, operations, sharedData, propertyMap, ((BaseAllocator) allocator).objectArraySize, ((BaseAllocator) allocator).objectFieldSize,
+    protected ShapeImpl(Layout layout, ShapeImpl parent, ObjectType operations, Object sharedData, PropertyMap propertyMap, Transition transition, Allocator allocator, int id) {
+        this(layout, parent, operations, sharedData, propertyMap, transition, ((BaseAllocator) allocator).objectArraySize, ((BaseAllocator) allocator).objectFieldSize,
                         ((BaseAllocator) allocator).primitiveFieldSize, ((BaseAllocator) allocator).primitiveArraySize, ((BaseAllocator) allocator).hasPrimitiveArray, id);
     }
 
     @SuppressWarnings("hiding")
-    protected abstract ShapeImpl createShape(Layout layout, Object sharedData, ShapeImpl parent, ObjectType operations, PropertyMap propertyMap, Allocator allocator, int id);
+    protected abstract ShapeImpl createShape(Layout layout, Object sharedData, ShapeImpl parent, ObjectType operations, PropertyMap propertyMap, Transition transition, Allocator allocator, int id);
 
     protected ShapeImpl(Layout layout, ObjectType operations, Object sharedData, int id) {
-        this(layout, null, operations, sharedData, PropertyMap.empty(), layout.createAllocator(), id);
+        this(layout, null, operations, sharedData, PropertyMap.empty(), null, layout.createAllocator(), id);
     }
 
     private static int makePropertyCount(ShapeImpl parent, PropertyMap propertyMap) {
@@ -235,7 +242,7 @@
     public final ShapeImpl getShapeFromProperty(Object propertyName) {
         ShapeImpl current = this;
         while (current != getRoot()) {
-            if (current.getLastProperty().getKey().equals(propertyName)) {
+            if (current.getTransitionFromParent() instanceof AddPropertyTransition && ((AddPropertyTransition) current.getTransitionFromParent()).getProperty().getKey().equals(propertyName)) {
                 return current;
             }
             current = current.getParent();
@@ -250,7 +257,7 @@
     public final ShapeImpl getShapeFromProperty(Property prop) {
         ShapeImpl current = this;
         while (current != getRoot()) {
-            if (current.getLastProperty().equals(prop)) {
+            if (current.getTransitionFromParent() instanceof AddPropertyTransition && ((AddPropertyTransition) current.getTransitionFromParent()).getProperty().equals(prop)) {
                 return current;
             }
             current = current.parent;
@@ -280,13 +287,13 @@
         return null;
     }
 
-    protected final void addTransition(Transition transition, ShapeImpl next) {
-        assert next.getParent() == this;
+    protected final void addDirectTransition(Transition transition, ShapeImpl next) {
+        assert next.getParent() == this && transition.isDirect();
         addTransitionInternal(transition, next);
     }
 
-    public final void addNonlinearTransition(Transition transition, ShapeImpl next) {
-        assert next.getParent() != this;
+    public final void addIndirectTransition(Transition transition, ShapeImpl next) {
+        assert next.getParent() != this && !transition.isDirect();
         addTransitionInternal(transition, next);
     }
 
@@ -311,6 +318,17 @@
         return propertyMap;
     }
 
+    private ShapeImpl queryTransition(Transition transition) {
+        ShapeImpl cachedShape = this.getTransitionMapForRead().get(transition);
+        if (cachedShape != null) { // Shape already exists?
+            shapeCacheHitCount.inc();
+            return (ShapeImpl) layout.getStrategy().returnCached(cachedShape);
+        }
+        shapeCacheMissCount.inc();
+
+        return null;
+    }
+
     /**
      * Add a new property in the map, yielding a new or cached Shape object.
      *
@@ -340,24 +358,21 @@
         assert !getPropertyListInternal(false).contains(prop);
         // invalidatePropertyAssumption(prop.getName());
 
-        Transition.AddTransition key = new Transition.AddTransition(prop);
-        Map<Transition, ShapeImpl> transitionMapForRead = this.getTransitionMapForRead();
-        ShapeImpl cachedShape = transitionMapForRead.get(key);
-        if (cachedShape != null) { // Shape already exists?
-            shapeCacheHitCount.inc();
-            return (ShapeImpl) layout.getStrategy().returnCached(cachedShape);
+        AddPropertyTransition addTransition = new AddPropertyTransition(prop);
+        ShapeImpl cachedShape = queryTransition(addTransition);
+        if (cachedShape != null) {
+            return cachedShape;
         }
-        shapeCacheMissCount.inc();
 
         ShapeImpl oldShape = (ShapeImpl) layout.getStrategy().ensureSpace(this, prop.getLocation());
 
-        ShapeImpl newShape = makeShapeWithAddedProperty(oldShape, key);
-        oldShape.addTransition(key, newShape);
+        ShapeImpl newShape = makeShapeWithAddedProperty(oldShape, addTransition);
+        oldShape.addDirectTransition(addTransition, newShape);
         return newShape;
     }
 
     protected ShapeImpl cloneRoot(ShapeImpl from, Object newSharedData) {
-        return createShape(from.layout, newSharedData, null, from.objectType, from.propertyMap, from.allocator(), from.id);
+        return createShape(from.layout, newSharedData, null, from.objectType, from.propertyMap, null, from.allocator(), from.id);
     }
 
     /**
@@ -367,34 +382,29 @@
      */
     protected final ShapeImpl cloneOnto(ShapeImpl newParent) {
         ShapeImpl from = this;
-        ShapeImpl newShape = createShape(newParent.layout, newParent.sharedData, newParent, from.objectType, from.propertyMap, from.allocator(), newParent.id);
+        ShapeImpl newShape = createShape(newParent.layout, newParent.sharedData, newParent, from.objectType, from.propertyMap, from.transitionFromParent, from.allocator(), newParent.id);
 
         shapeCloneCount.inc();
 
         // (aw) need to have this transition for obsolescence
-        newParent.addTransition(getTransitionFromParent(), newShape);
+        newParent.addDirectTransition(from.transitionFromParent, newShape);
         return newShape;
     }
 
-    private Transition getTransitionFromParent() {
-        for (Map.Entry<Transition, ShapeImpl> property : parent.getTransitionMapForRead().entrySet()) {
-            if (property.getValue() == this) {
-                return property.getKey();
-            }
-        }
-        throw new NoSuchElementException();
+    public final Transition getTransitionFromParent() {
+        return transitionFromParent;
     }
 
     /**
      * Create a new shape that adds a property to the parent shape.
      */
-    private static ShapeImpl makeShapeWithAddedProperty(ShapeImpl parent, AddTransition addTransition) {
+    private static ShapeImpl makeShapeWithAddedProperty(ShapeImpl parent, AddPropertyTransition addTransition) {
         Property addend = addTransition.getProperty();
         BaseAllocator allocator = parent.allocator().addLocation(addend.getLocation());
 
         PropertyMap newPropertyMap = parent.propertyMap.putCopy(addend);
 
-        ShapeImpl newShape = parent.createShape(parent.layout, parent.sharedData, parent, parent.objectType, newPropertyMap, allocator, parent.id);
+        ShapeImpl newShape = parent.createShape(parent.layout, parent.sharedData, parent, parent.objectType, newPropertyMap, addTransition, allocator, parent.id);
         assert ((LocationImpl) addend.getLocation()).primitiveArrayCount() == 0 || newShape.hasPrimitiveArray;
         assert newShape.depth == allocator.depth;
         return newShape;
@@ -403,11 +413,11 @@
     /**
      * Create a new shape that reserves the primitive extension array field.
      */
-    private static ShapeImpl makeShapeWithPrimitiveExtensionArray(ShapeImpl parent) {
+    private static ShapeImpl makeShapeWithPrimitiveExtensionArray(ShapeImpl parent, Transition transition) {
         assert parent.getLayout().hasPrimitiveExtensionArray();
         assert !parent.hasPrimitiveArray();
         BaseAllocator allocator = parent.allocator().addLocation(parent.getLayout().getPrimitiveArrayLocation());
-        ShapeImpl newShape = parent.createShape(parent.layout, parent.sharedData, parent, parent.objectType, parent.propertyMap, allocator, parent.id);
+        ShapeImpl newShape = parent.createShape(parent.layout, parent.sharedData, parent, parent.objectType, parent.propertyMap, transition, allocator, parent.id);
         assert newShape.hasPrimitiveArray();
         assert newShape.depth == allocator.depth;
         return newShape;
@@ -415,17 +425,15 @@
 
     private ShapeImpl addPrimitiveExtensionArray() {
         assert layout.hasPrimitiveExtensionArray() && !hasPrimitiveArray();
-        Transition key = new Transition.ReservePrimitiveArrayTransition();
-        ShapeImpl cachedShape = this.getTransitionMapForRead().get(key);
+        Transition transition = new ReservePrimitiveArrayTransition();
+        ShapeImpl cachedShape = queryTransition(transition);
         if (cachedShape != null) {
-            shapeCacheHitCount.inc();
-            return (ShapeImpl) layout.getStrategy().returnCached(cachedShape);
+            return cachedShape;
         }
-        shapeCacheMissCount.inc();
 
         ShapeImpl oldShape = (ShapeImpl) layout.getStrategy().ensureSpace(this, layout.getPrimitiveArrayLocation());
-        ShapeImpl newShape = makeShapeWithPrimitiveExtensionArray(oldShape);
-        oldShape.addTransition(key, newShape);
+        ShapeImpl newShape = makeShapeWithPrimitiveExtensionArray(oldShape, transition);
+        oldShape.addDirectTransition(transition, newShape);
         return newShape;
     }
 
@@ -455,8 +463,7 @@
     @Override
     public final List<Property> getPropertyList(Pred<Property> filter) {
         LinkedList<Property> props = new LinkedList<>();
-        next: for (ShapeImpl current = this; current != getRoot(); current = current.parent) {
-            Property currentProperty = current.getLastProperty();
+        next: for (Property currentProperty : this.propertyMap.reverseOrderValues()) {
             if (!currentProperty.isHidden() && filter.test(currentProperty)) {
                 if (currentProperty.getLocation() instanceof DeclaredLocation) {
                     for (Iterator<Property> iter = props.iterator(); iter.hasNext();) {
@@ -488,11 +495,11 @@
     @Override
     public final List<Property> getPropertyListInternal(boolean ascending) {
         LinkedList<Property> props = new LinkedList<>();
-        for (ShapeImpl current = this; current != getRoot(); current = current.parent) {
+        for (Property current : this.propertyMap.reverseOrderValues()) {
             if (ascending) {
-                props.addFirst(current.getLastProperty());
+                props.addFirst(current);
             } else {
-                props.add(current.getLastProperty());
+                props.add(current);
             }
         }
         return props;
@@ -507,8 +514,7 @@
     @Override
     public final List<Object> getKeyList(Pred<Property> filter) {
         LinkedList<Object> keys = new LinkedList<>();
-        for (ShapeImpl current = this; current != getRoot(); current = current.parent) {
-            Property currentProperty = current.getLastProperty();
+        for (Property currentProperty : this.propertyMap.reverseOrderValues()) {
             if (!currentProperty.isHidden() && filter.test(currentProperty) && !currentProperty.isShadow()) {
                 keys.addFirst(currentProperty.getKey());
             }
@@ -526,12 +532,9 @@
         return getKeyList();
     }
 
-    public final void setTypeTransition(ShapeImpl successorShape, Property before, Property after) {
-        getTransitionMapForWrite().put(new Transition.TypeTransition(before, after), successorShape);
-    }
-
-    private static Assumption createValidAssumption() {
-        return Truffle.getRuntime().createAssumption("valid shape");
+    @Override
+    public final boolean isValid() {
+        return getValidAssumption().isValid();
     }
 
     @Override
@@ -539,27 +542,47 @@
         return validAssumption;
     }
 
+    private static Assumption createValidAssumption() {
+        return Truffle.getRuntime().createAssumption("valid shape");
+    }
+
+    public final void invalidateValidAssumption() {
+        getValidAssumption().invalidate();
+    }
+
     @Override
-    public final boolean isValid() {
-        return getValidAssumption().isValid();
+    public final boolean isLeaf() {
+        return leafAssumption == null || leafAssumption.isValid();
+    }
+
+    @Override
+    public final Assumption getLeafAssumption() {
+        if (leafAssumption == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            synchronized (getMutex()) {
+                if (leafAssumption == null) {
+                    leafAssumption = isLeafHelper() ? createLeafAssumption() : NeverValidAssumption.INSTANCE;
+                }
+            }
+        }
+        return leafAssumption;
+    }
+
+    private boolean isLeafHelper() {
+        return getTransitionMapForRead().isEmpty();
     }
 
     private static Assumption createLeafAssumption() {
         return Truffle.getRuntime().createAssumption("leaf shape");
     }
 
-    @Override
-    public final Assumption getLeafAssumption() {
-        return leafAssumption;
-    }
-
-    @Override
-    public final boolean isLeaf() {
-        return getLeafAssumption().isValid();
-    }
-
     private void invalidateLeafAssumption() {
-        getLeafAssumption().invalidate();
+        Assumption assumption = leafAssumption;
+        if (assumption != null) {
+            assumption.invalidate();
+        } else {
+            leafAssumption = NeverValidAssumption.INSTANCE;
+        }
     }
 
     @Override
@@ -611,24 +634,24 @@
     @TruffleBoundary
     @Override
     public final ShapeImpl removeProperty(Property prop) {
-        RemoveTransition transition = new RemoveTransition(prop);
-        ShapeImpl cachedShape = getTransitionMapForRead().get(transition);
+        RemovePropertyTransition transition = new RemovePropertyTransition(prop);
+        ShapeImpl cachedShape = queryTransition(transition);
         if (cachedShape != null) {
-            return (ShapeImpl) layout.getStrategy().returnCached(cachedShape);
+            return cachedShape;
         }
 
         ShapeImpl shape = getShapeFromProperty(prop);
         if (shape != null) {
-            List<Property> properties = new ArrayList<>();
+            List<Transition> transitionList = new ArrayList<>();
             ShapeImpl current = this;
             while (current != shape) {
-                properties.add(current.getLastProperty());
+                transitionList.add(current.getTransitionFromParent());
                 current = current.parent;
             }
             ShapeImpl newShape = shape.parent;
-            for (ListIterator<Property> iterator = properties.listIterator(properties.size()); iterator.hasPrevious();) {
-                Property previous = iterator.previous();
-                newShape = newShape.append(previous);
+            for (ListIterator<Transition> iterator = transitionList.listIterator(transitionList.size()); iterator.hasPrevious();) {
+                Transition previous = iterator.previous();
+                newShape = newShape.applyTransition(previous, true);
             }
 
             getTransitionMapForWrite().put(transition, newShape);
@@ -644,6 +667,18 @@
         return addProperty(oldProperty.relocate(allocator().moveLocation(oldProperty.getLocation())));
     }
 
+    public final ShapeImpl applyTransition(Transition transition, boolean append) {
+        if (transition instanceof AddPropertyTransition) {
+            return append ? append(((AddPropertyTransition) transition).getProperty()) : addProperty(((AddPropertyTransition) transition).getProperty());
+        } else if (transition instanceof ObjectTypeTransition) {
+            return changeType(((ObjectTypeTransition) transition).getObjectType());
+        } else if (transition instanceof ReservePrimitiveArrayTransition) {
+            return reservePrimitiveExtensionArray();
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
     @Override
     public final BaseAllocator allocator() {
         return layout.getStrategy().createAllocator(this);
@@ -653,27 +688,34 @@
      * Duplicate shape exchanging existing property with new property.
      */
     @Override
-    public final ShapeImpl replaceProperty(Property oldProperty, Property newProp) {
+    public final ShapeImpl replaceProperty(Property oldProperty, Property newProperty) {
+        Transition replacePropertyTransition = new Transition.ReplacePropertyTransition(oldProperty, newProperty);
+        ShapeImpl cachedShape = queryTransition(replacePropertyTransition);
+        if (cachedShape != null) {
+            return cachedShape;
+        }
+
         ShapeImpl top = this;
-        List<Property> propertyList = new ArrayList<>();
+        List<Transition> transitionList = new ArrayList<>();
         boolean found = false;
         while (top != getRoot() && !found) {
-            Property prop = top.getLastProperty();
-            propertyList.add(prop);
-            if (prop.getKey().equals(newProp.getKey())) {
+            Transition transition = top.getTransitionFromParent();
+            transitionList.add(transition);
+            if (transition instanceof AddPropertyTransition && ((AddPropertyTransition) transition).getProperty().getKey().equals(newProperty.getKey())) {
                 found = true;
             }
             top = top.parent;
         }
         ShapeImpl newShape = top;
-        for (ListIterator<Property> iterator = propertyList.listIterator(propertyList.size()); iterator.hasPrevious();) {
-            Property prop = iterator.previous();
-            if (prop.getKey().equals(newProp.getKey())) {
-                newShape = newShape.addProperty(newProp);
+        for (ListIterator<Transition> iterator = transitionList.listIterator(transitionList.size()); iterator.hasPrevious();) {
+            Transition transition = iterator.previous();
+            if (transition instanceof AddPropertyTransition && ((AddPropertyTransition) transition).getProperty().getKey().equals(newProperty.getKey())) {
+                newShape = newShape.addProperty(newProperty);
             } else {
-                newShape = newShape.addProperty(prop);
+                newShape = newShape.applyTransition(transition, false);
             }
         }
+        addIndirectTransition(replacePropertyTransition, newShape);
         return newShape;
     }
 
@@ -725,9 +767,6 @@
         return newShape;
     }
 
-    /**
-     * NB: this is not an accurate property count.
-     */
     @Override
     public final int getPropertyCount() {
         return propertyCount;
@@ -809,19 +848,19 @@
     @Override
     @TruffleBoundary
     public final ShapeImpl changeType(ObjectType newOps) {
-        OperationsTransition transition = new OperationsTransition(newOps);
-        ShapeImpl cachedShape = getTransitionMapForRead().get(transition);
+        ObjectTypeTransition transition = new ObjectTypeTransition(newOps);
+        ShapeImpl cachedShape = queryTransition(transition);
         if (cachedShape != null) {
             return cachedShape;
-        } else {
-            ShapeImpl newShape = createShape(layout, extraData, this, newOps, propertyMap, allocator(), id);
-            addTransition(transition, newShape);
-            return newShape;
         }
+
+        ShapeImpl newShape = createShape(layout, sharedData, this, newOps, propertyMap, transition, allocator(), id);
+        addDirectTransition(transition, newShape);
+        return newShape;
     }
 
     @Override
-    public final Shape reservePrimitiveExtensionArray() {
+    public final ShapeImpl reservePrimitiveExtensionArray() {
         if (layout.hasPrimitiveExtensionArray() && !hasPrimitiveArray()) {
             return addPrimitiveExtensionArray();
         }
--- a/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/Transition.java	Fri Dec 05 11:09:57 2014 +0100
+++ b/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/Transition.java	Sun Dec 07 20:43:33 2014 +0100
@@ -47,6 +47,8 @@
         return true;
     }
 
+    public abstract boolean isDirect();
+
     public abstract static class PropertyTransition extends Transition {
         private final Property property;
 
@@ -79,47 +81,62 @@
         }
     }
 
-    public static final class AddTransition extends PropertyTransition {
-        public AddTransition(Property property) {
+    public static final class AddPropertyTransition extends PropertyTransition {
+        public AddPropertyTransition(Property property) {
             super(property);
         }
+
+        @Override
+        public boolean isDirect() {
+            return true;
+        }
     }
 
-    public static final class RemoveTransition extends PropertyTransition {
-        public RemoveTransition(Property property) {
+    public static final class RemovePropertyTransition extends PropertyTransition {
+        public RemovePropertyTransition(Property property) {
             super(property);
         }
+
+        @Override
+        public boolean isDirect() {
+            return false;
+        }
     }
 
-    public static final class OperationsTransition extends Transition {
-        private final ObjectType operations;
+    public static final class ObjectTypeTransition extends Transition {
+        private final ObjectType objectType;
 
-        public OperationsTransition(ObjectType operations) {
-            this.operations = operations;
+        public ObjectTypeTransition(ObjectType objectType) {
+            this.objectType = objectType;
         }
 
-        public ObjectType getOperations() {
-            return operations;
+        public ObjectType getObjectType() {
+            return objectType;
         }
 
         @Override
         public boolean equals(Object other) {
-            return super.equals(other) && Objects.equals(operations, ((OperationsTransition) other).operations);
+            return super.equals(other) && Objects.equals(objectType, ((ObjectTypeTransition) other).objectType);
         }
 
         @Override
         public int hashCode() {
             final int prime = 31;
             int result = super.hashCode();
-            result = prime * result + ((operations == null) ? 0 : operations.hashCode());
+            result = prime * result + ((objectType == null) ? 0 : objectType.hashCode());
             return result;
         }
+
+        @Override
+        public boolean isDirect() {
+            return true;
+        }
     }
 
-    public static final class TypeTransition extends PropertyTransition {
+    public static final class ReplacePropertyTransition extends PropertyTransition {
         private final Property after;
 
-        public TypeTransition(Property before, Property after) {
+        public ReplacePropertyTransition(Property before, Property after) {
             super(before);
             this.after = after;
         }
@@ -131,11 +148,21 @@
         public Property getPropertyAfter() {
             return after;
         }
+
+        @Override
+        public boolean isDirect() {
+            return false;
+        }
     }
 
     public static final class ReservePrimitiveArrayTransition extends Transition {
         public ReservePrimitiveArrayTransition() {
         }
+
+        @Override
+        public boolean isDirect() {
+            return true;
+        }
     }
 
     public String getShortName() {
--- a/make/Makefile	Fri Dec 05 11:09:57 2014 +0100
+++ b/make/Makefile	Sun Dec 07 20:43:33 2014 +0100
@@ -306,9 +306,20 @@
 			$(MAKE_ARGS) $(VM_TARGET) 
 
 
+
+ifeq (, $(shell python2.7 --version 2>/dev/null && echo ok))
+  ifeq (, $(shell python2.6 --version 2>/dev/null && echo ok))
+    PYTHON=python
+  else
+    PYTHON=python2.6
+  endif
+else
+  PYTHON=python2.7
+endif
+
 # Builds code that can be shared among different build flavors
 buildshared:
-	python2 -u $(GAMMADIR)/mxtool/mx.py build --no-native --export-dir $(SHARED_DIR)
+	$(PYTHON) -u $(GAMMADIR)/mxtool/mx.py build --no-native --export-dir $(SHARED_DIR)
 
 # Export file rule
 generic_export: $(EXPORT_LIST)
--- a/mx/mx_graal.py	Fri Dec 05 11:09:57 2014 +0100
+++ b/mx/mx_graal.py	Sun Dec 07 20:43:33 2014 +0100
@@ -755,7 +755,7 @@
         if not exists(opts2.export_dir):
             os.makedirs(opts2.export_dir)
         else:
-            assert os.path.isdir(opts2.export_dir), '{} is not a directory'.format(opts2.export_dir)
+            assert os.path.isdir(opts2.export_dir), '{0} is not a directory'.format(opts2.export_dir)
 
         defsPath = join(_graal_home, 'make', 'defs.make')
         with open(defsPath) as fp:
@@ -1438,7 +1438,7 @@
 
     with VM('server', 'product'):  # hosted mode
         with Task('UnitTests:hosted-product', tasks):
-            unittest(['--enable-timing', '--verbose'])
+            unittest(['--enable-timing', '--verbose', '--fail-fast'])
 
     with VM('server', 'product'):  # hosted mode
         with Task('UnitTests-BaselineCompiler:hosted-product', tasks):
@@ -1835,7 +1835,7 @@
                         deps = d['deps']
                         makejmhdep(artifactId, groupId, deps)
             except ValueError as e:
-                mx.abort('Error parsing {}:\n{}'.format(f, e))
+                mx.abort('Error parsing {0}:\n{1}'.format(f, e))
 
 def buildjmh(args):
     """build the JMH benchmarks"""
@@ -1916,7 +1916,7 @@
                 else:
                     jmhArgs[n] = v
         except ValueError as e:
-            mx.abort('error parsing JSON input: {}\n{}'.format(j, e))
+            mx.abort('error parsing JSON input: {0}\n{1}'.format(j, e))
 
     jmhPath = _get_jmh_path()
     mx.log('Using benchmarks in ' + jmhPath)
@@ -2271,13 +2271,14 @@
     assert exists(findbugsJar)
     nonTestProjects = [p for p in mx.projects() if not p.name.endswith('.test') and not p.name.endswith('.jtt')]
     outputDirs = map(mx._cygpathU2W, [p.output_dir() for p in nonTestProjects])
+    javaCompliance = max([p.javaCompliance for p in nonTestProjects])
     findbugsResults = join(_graal_home, 'findbugs.results')
 
     cmd = ['-jar', mx._cygpathU2W(findbugsJar), '-textui', '-low', '-maxRank', '15']
     if sys.stdout.isatty():
         cmd.append('-progress')
     cmd = cmd + ['-auxclasspath', mx._separatedCygpathU2W(mx.classpath([d.name for d in _jdkDeployedDists] + [p.name for p in nonTestProjects])), '-output', mx._cygpathU2W(findbugsResults), '-exitcode'] + args + outputDirs
-    exitcode = mx.run_java(cmd, nonZeroIsFatal=False)
+    exitcode = mx.run_java(cmd, nonZeroIsFatal=False, javaConfig=mx.java(javaCompliance))
     if exitcode != 0:
         with open(findbugsResults) as fp:
             mx.log(fp.read())
@@ -2309,7 +2310,7 @@
                                         if not matcher.match(content):
                                             failures[f] = csConfig
     for n, v in failures.iteritems():
-        mx.log('{}: header does not match RegexpHeader defined in {}'.format(n, v))
+        mx.log('{0}: header does not match RegexpHeader defined in {1}'.format(n, v))
     return len(failures)
 
 def mx_init(suite):
--- a/mxtool/mx.py	Fri Dec 05 11:09:57 2014 +0100
+++ b/mxtool/mx.py	Sun Dec 07 20:43:33 2014 +0100
@@ -109,7 +109,7 @@
         try:
             excl = [dependency(d) for d in self.excludedDependencies]
         except SystemExit as e:
-            abort('invalid excluded dependency for {} distribution: {}'.format(self.name, e))
+            abort('invalid excluded dependency for {0} distribution: {1}'.format(self.name, e))
         return deps + [d for d in sorted_deps(self.deps, includeLibs=includeLibs) if d not in excl]
 
     def __str__(self):
@@ -698,14 +698,14 @@
         abspath = _make_absolute(path, self.suite.dir)
         if not optional and not exists(abspath):
             if not len(urls):
-                abort('Non-optional library {} must either exist at {} or specify one or more URLs from which it can be retrieved'.format(name, abspath))
+                abort('Non-optional library {0} must either exist at {1} or specify one or more URLs from which it can be retrieved'.format(name, abspath))
 
         def _checkSha1PropertyCondition(propName, cond, inputPath):
             if not cond:
                 absInputPath = _make_absolute(inputPath, self.suite.dir)
                 if exists(absInputPath):
-                    abort('Missing "{}" property for library {}. Add the following line to projects file:\nlibrary@{}@{}={}'.format(propName, name, name, propName, sha1OfFile(absInputPath)))
-                abort('Missing "{}" property for library {}'.format(propName, name))
+                    abort('Missing "{0}" property for library {1}. Add the following line to projects file:\nlibrary@{2}@{3}={4}'.format(propName, name, name, propName, sha1OfFile(absInputPath)))
+                abort('Missing "{0}" property for library {1}'.format(propName, name))
 
         _checkSha1PropertyCondition('sha1', sha1, path)
         _checkSha1PropertyCondition('sourceSha1', not sourcePath or sourceSha1, sourcePath)
@@ -880,7 +880,7 @@
                     if not existing:
                         suite[s] = additional
                     else:
-                        conflicting = additional.keys() & existing.keys()
+                        conflicting = frozenset(additional.keys()) & frozenset(existing.keys())
                         if conflicting:
                             abort(modulePath + ' redefines: ' + ', '.join(conflicting))
                         existing.update(additional)
@@ -1181,12 +1181,12 @@
                     finally:
                         d.optional = True
                     if not path:
-                        logv('[omitting optional library {} as {} does not exist]'.format(d, d.path))
+                        logv('[omitting optional library {0} as {1} does not exist]'.format(d, d.path))
                         del _libs[d.name]
                         self.libs.remove(d)
             elif d.isProject():
                 if java(d.javaCompliance) is None:
-                    logv('[omitting project {} as Java compliance {} cannot be satisfied by configured JDKs]'.format(d, d.javaCompliance))
+                    logv('[omitting project {0} as Java compliance {1} cannot be satisfied by configured JDKs]'.format(d, d.javaCompliance))
                     del _projects[d.name]
                     self.projects.remove(d)
                 else:
@@ -1195,19 +1195,19 @@
                         if jreLib:
                             if not jreLib.is_present_in_jdk(java(d.javaCompliance)):
                                 if jreLib.optional:
-                                    logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+                                    logv('[omitting project {0} as dependency {1} is missing]'.format(d, name))
                                     del _projects[d.name]
                                     self.projects.remove(d)
                                 else:
-                                    abort('JRE library {} required by {} not found'.format(jreLib, d))
+                                    abort('JRE library {0} required by {1} not found'.format(jreLib, d))
                         elif not dependency(name, fatalIfMissing=False):
-                            logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+                            logv('[omitting project {0} as dependency {1} is missing]'.format(d, name))
                             del _projects[d.name]
                             self.projects.remove(d)
         for dist in _dists.itervalues():
             for name in list(dist.deps):
                 if not dependency(name, fatalIfMissing=False):
-                    logv('[omitting {} from distribution {}]'.format(name, dist))
+                    logv('[omitting {0} from distribution {1}]'.format(name, dist))
                     dist.deps.remove(name)
 
         if hasattr(self, 'mx_post_parse_cmd_line'):
@@ -1673,6 +1673,9 @@
 
         opts = self.parse_args()
 
+        global _opts
+        _opts = opts
+
         # Give the timeout options a default value to avoid the need for hasattr() tests
         opts.__dict__.setdefault('timeout', 0)
         opts.__dict__.setdefault('ptimeout', 0)
@@ -2209,7 +2212,7 @@
     the object's value is printed and the exit status is one.
     """
 
-    if _opts.killwithsigquit:
+    if _opts and _opts.killwithsigquit:
         _send_sigquit()
 
     def is_alive(p):
@@ -2227,7 +2230,7 @@
                     _kill_process_group(p.pid, signal.SIGKILL)
             except BaseException as e:
                 if is_alive(p):
-                    log('error while killing subprocess {} "{}": {}'.format(p.pid, ' '.join(args), e))
+                    log('error while killing subprocess {0} "{1}": {2}'.format(p.pid, ' '.join(args), e))
 
     if _opts and _opts.verbose:
         import traceback
@@ -2304,7 +2307,7 @@
         return self.proj.name
 
     def logCompilation(self, compiler):
-        log('Compiling Java sources for {} with {}... [{}]'.format(self.proj.name, compiler, self.reason))
+        log('Compiling Java sources for {0} with {1}... [{2}]'.format(self.proj.name, compiler, self.reason))
 
     def execute(self):
         argfileName = join(self.proj.dir, 'javafilelist.txt')
@@ -2688,8 +2691,8 @@
         failed += joinTasks(active)
         if len(failed):
             for t in failed:
-                log('Compiling {} failed'.format(t.proj.name))
-            abort('{} Java compilation tasks failed'.format(len(failed)))
+                log('Compiling {0} failed'.format(t.proj.name))
+            abort('{0} Java compilation tasks failed'.format(len(failed)))
 
     if args.java:
         for dist in sorted_dists():
@@ -3039,7 +3042,7 @@
                     candidates.difference_update(c.all_deps([], False, False))
                 candidates = [d.name for d in candidates]
 
-                abort('{} does not use any packages defined in these projects: {}\nComputed project dependencies: {}'.format(
+                abort('{0} does not use any packages defined in these projects: {1}\nComputed project dependencies: {2}'.format(
                     p, ', '.join(ignoredDeps), ','.join(candidates)))
 
             excess = frozenset(p.deps) - set(p.canonical_deps())
@@ -3166,7 +3169,7 @@
                                 if name == 'file':
                                     source[0] = attrs['name']
                                 elif name == 'error':
-                                    errors.append('{}:{}: {}'.format(source[0], attrs['line'], attrs['message']))
+                                    errors.append('{0}:{1}: {2}'.format(source[0], attrs['line'], attrs['message']))
 
                             xp = xml.parsers.expat.ParserCreate()
                             xp.StartElementHandler = start_element
@@ -4782,9 +4785,9 @@
                 if not 'version' in subprocess.check_output(['dot', '-V'], stderr=subprocess.STDOUT):
                     dotErr = 'dot -V does not print a string containing "version"'
             except subprocess.CalledProcessError as e:
-                dotErr = 'error calling "dot -V": {}'.format(e)
+                dotErr = 'error calling "dot -V": {0}'.format(e)
             except OSError as e:
-                dotErr = 'error calling "dot -V": {}'.format(e)
+                dotErr = 'error calling "dot -V": {0}'.format(e)
 
             if dotErr != None:
                 abort('cannot generate dependency graph: ' + dotErr)
@@ -4824,7 +4827,7 @@
 
             # Create HTML that embeds the svg file in an <object> frame
             with open(html, 'w') as fp:
-                print >> fp, '<html><body><object data="{}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base)
+                print >> fp, '<html><body><object data="{0}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base)
 
         if exists(args.base):
             shutil.rmtree(args.base)
@@ -5177,9 +5180,9 @@
         abort('no primary suite found')
 
     opts, commandAndArgs = _argParser._parse_cmd_line()
-
-    global _opts, _java_homes
-    _opts = opts
+    assert _opts == opts
+
+    global _java_homes
     defaultJdk = JavaConfig(opts.java_home, opts.java_dbg_port)
     _java_homes = [defaultJdk]
     if opts.extra_java_homes:
--- a/src/cpu/x86/vm/nativeInst_x86.hpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/cpu/x86/vm/nativeInst_x86.hpp	Sun Dec 07 20:43:33 2014 +0100
@@ -562,26 +562,24 @@
                                                           (ubyte_at(0) & 0xF0) == 0x70;  /* short jump */ }
 inline bool NativeInstruction::is_safepoint_poll() {
 #ifdef AMD64
-  if (Assembler::is_polling_page_far()) {
-    // two cases, depending on the choice of the base register in the address.
-    if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix &&
-         ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl &&
-         (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) ||
-        ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
-        (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) {
-      return true;
-    } else {
-      return false;
-    }
-  } else {
-    if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
-        ubyte_at(1) == 0x05) { // 00 rax 101
-      address fault = addr_at(6) + int_at(2);
-      return os::is_poll_address(fault);
-    } else {
-      return false;
-    }
+  // Try decoding a near safepoint first:
+  if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
+      ubyte_at(1) == 0x05) { // 00 rax 101
+    address fault = addr_at(6) + int_at(2);
+    NOT_GRAAL(assert(!Assembler::is_polling_page_far(), "unexpected poll encoding");)
+    return os::is_poll_address(fault);
   }
+  // Now try decoding a far safepoint:
+  // two cases, depending on the choice of the base register in the address.
+  if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix &&
+       ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl &&
+       (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) ||
+      ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
+      (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) {
+    NOT_GRAAL(assert(Assembler::is_polling_page_far(), "unexpected poll encoding");)
+    return true;
+  }
+  return false;
 #else
   return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2reg ||
            ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl ) &&
--- a/src/share/vm/classfile/systemDictionary.cpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/classfile/systemDictionary.cpp	Sun Dec 07 20:43:33 2014 +0100
@@ -96,6 +96,10 @@
 oop SystemDictionary::graal_loader() {
   return _graal_loader;
 }
+void SystemDictionary::init_graal_loader(oop loader) {
+  assert(UseGraalClassLoader == (loader != NULL), "must be");
+  _graal_loader = loader;
+}
 #endif
 
 // lazily initialized klass variables
@@ -1931,18 +1935,6 @@
   }
 }
 
-#ifdef GRAAL
-void SystemDictionary::initialize_preloaded_graal_classes(TRAPS) {
-  assert(WK_KLASS(CompilerThread_klass) == NULL, "preloaded Graal classes should only be initialized once");
-  if (UseGraalClassLoader) {
-    _graal_loader = GraalRuntime::compute_graal_class_loader(CHECK);
-  }
-
-  WKID scan = FIRST_GRAAL_WKID;
-  initialize_wk_klasses_through(LAST_GRAAL_WKID, scan, CHECK);
-}
-#endif
-
 // Tells if a given klass is a box (wrapper class, such as java.lang.Integer).
 // If so, returns the basic type it holds.  If not, returns T_OBJECT.
 BasicType SystemDictionary::box_klass_type(Klass* k) {
--- a/src/share/vm/classfile/systemDictionary.hpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Sun Dec 07 20:43:33 2014 +0100
@@ -185,8 +185,7 @@
                                                                                                                          \
   /* Support for Graal */                                                                                                \
   do_klass(BitSet_klass,                                java_util_BitSet,                          Opt                 ) \
-  /* Graal classes */                                                                                                    \
-  GRAAL_ONLY(do_klass(CompilerThread_klass,                  com_oracle_graal_compiler_CompilerThread,                     Graal)) \
+  /* Graal classes. These are loaded on-demand. */                                                                                 \
   GRAAL_ONLY(do_klass(Node_klass,                            com_oracle_graal_graph_Node,                                  Graal)) \
   GRAAL_ONLY(do_klass(NodeClass_klass,                       com_oracle_graal_graph_NodeClass,                             Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompiledCode_klass,             com_oracle_graal_hotspot_HotSpotCompiledCode,                 Graal)) \
@@ -262,7 +261,7 @@
     WKID_LIMIT,
 
 #ifdef GRAAL
-    FIRST_GRAAL_WKID = WK_KLASS_ENUM_NAME(CompilerThread_klass),
+    FIRST_GRAAL_WKID = WK_KLASS_ENUM_NAME(Node_klass),
     LAST_GRAAL_WKID  = WK_KLASS_ENUM_NAME(AbstractValue_klass),
 #endif
 
@@ -538,6 +537,8 @@
   // Returns the Graal loader. This will be NULL if !UseGraalClassLoader
   // in which case it's equivalent to the boot loader
   static oop graal_loader();
+  // Sets the Graal loader. This is called at most once.
+  static void init_graal_loader(oop loader);
 #endif
 
   // Compute the default system loader
@@ -705,10 +706,6 @@
 public:
   static bool is_ext_class_loader(Handle class_loader);
 
-#ifdef GRAAL
-  static void initialize_preloaded_graal_classes(TRAPS);
-#endif
-
 private:
   static Klass* find_shared_class(Symbol* class_name);
 
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Sun Dec 07 20:43:33 2014 +0100
@@ -291,7 +291,6 @@
                                                                                                                                       \
   /* Support for Graal */                                                                                                             \
   template(java_util_BitSet,                                         "java/util/BitSet")                                              \
-  GRAAL_ONLY(template(com_oracle_graal_compiler_CompilerThread,                 "com/oracle/graal/compiler/CompilerThread"))                      \
   GRAAL_ONLY(template(com_oracle_graal_graph_Node,                              "com/oracle/graal/graph/Node"))                                   \
   GRAAL_ONLY(template(com_oracle_graal_graph_NodeClass,                         "com/oracle/graal/graph/NodeClass"))                              \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotGraalRuntime,             "com/oracle/graal/hotspot/HotSpotGraalRuntime"))                  \
--- a/src/share/vm/graal/graalCompiler.cpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Sun Dec 07 20:43:33 2014 +0100
@@ -115,6 +115,7 @@
       return;
   }
 
+  GraalRuntime::ensure_graal_class_loader_is_initialized();
   HandleMark hm;
   ResourceMark rm;
   JavaValue result(T_VOID);
--- a/src/share/vm/graal/graalRuntime.cpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/graal/graalRuntime.cpp	Sun Dec 07 20:43:33 2014 +0100
@@ -49,6 +49,8 @@
   AMD64_ONLY(guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"));
   NOT_LP64(error("check TLAB allocation code for address space conflicts"));
 
+  ensure_graal_class_loader_is_initialized();
+
   JavaThread* THREAD = JavaThread::current();
   {
     ThreadToNativeFromVM trans(THREAD);
@@ -656,6 +658,13 @@
   return value;
 JRT_END
 
+// private static void Factory.init()
+JVM_ENTRY(void, JVM_InitGraalClassLoader(JNIEnv *env, jclass c, jobject loader_handle))
+  SystemDictionary::init_graal_loader(JNIHandles::resolve(loader_handle));
+  SystemDictionary::WKID scan = SystemDictionary::FIRST_GRAAL_WKID;
+  SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_GRAAL_WKID, scan, CHECK);
+JVM_END
+
 // private static GraalRuntime Graal.initializeRuntime()
 JVM_ENTRY(jobject, JVM_GetGraalRuntime(JNIEnv *env, jclass c))
   return GraalRuntime::get_HotSpotGraalRuntime_jobject();
@@ -670,6 +679,7 @@
 
 // private static TruffleRuntime Truffle.createRuntime()
 JVM_ENTRY(jobject, JVM_CreateTruffleRuntime(JNIEnv *env, jclass c))
+  GraalRuntime::ensure_graal_class_loader_is_initialized();
   TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime", CHECK_NULL);
   KlassHandle klass = GraalRuntime::resolve_or_fail(name, CHECK_NULL);
 
@@ -748,6 +758,48 @@
   return result;
 JVM_END
 
+
+void GraalRuntime::ensure_graal_class_loader_is_initialized() {
+  // This initialization code is guarded by a static pointer to the Factory class.
+  // Once it is non-null, the Graal class loader and well known Graal classes are
+  // guaranteed to have been initialized. By going through the static
+  // initializer of Factory, we can rely on class initialization semantics to
+  // synchronize threads racing to do the initialization.
+  static Klass* _FactoryKlass = NULL;
+  if (_FactoryKlass == NULL) {
+    Thread* THREAD = Thread::current();
+    TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/loader/Factory", CHECK_ABORT);
+    KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      static volatile int seen_error = 0;
+      if (!seen_error && Atomic::cmpxchg(1, &seen_error, 0) == 0) {
+        // Only report the failure on the first thread that hits it
+        abort_on_pending_exception(PENDING_EXCEPTION, "Graal classes are not available");
+      } else {
+        CLEAR_PENDING_EXCEPTION;
+        // Give first thread time to report the error.
+        os::sleep(THREAD, 100, false);
+        vm_abort(false);
+      }
+    }
+
+    // We cannot use graalJavaAccess for this because we are currently in the
+    // process of initializing that mechanism.
+    TempNewSymbol field_name = SymbolTable::new_symbol("useGraalClassLoader", CHECK_ABORT);
+    fieldDescriptor field_desc;
+    if (klass->find_field(field_name, vmSymbols::bool_signature(), &field_desc) == NULL) {
+      ResourceMark rm;
+      fatal(err_msg("Invalid layout of %s at %s", field_name->as_C_string(), klass->external_name()));
+    }
+
+    InstanceKlass* ik = InstanceKlass::cast(klass());
+    address addr = ik->static_field_addr(field_desc.offset() - InstanceMirrorKlass::offset_of_static_fields());
+    *((jboolean *) addr) = (jboolean) UseGraalClassLoader;
+    klass->initialize(CHECK_ABORT);
+    _FactoryKlass = klass();
+  }
+}
+
 jint GraalRuntime::check_arguments(TRAPS) {
   KlassHandle nullHandle;
   parse_arguments(nullHandle, THREAD);
@@ -800,6 +852,7 @@
 }
 
 void GraalRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) {
+  ensure_graal_class_loader_is_initialized();
   char first = arg[0];
   char* name;
   size_t name_len;
@@ -1017,17 +1070,6 @@
                           thread);
 }
 
-oop GraalRuntime::compute_graal_class_loader(TRAPS) {
-  assert(UseGraalClassLoader, "must be");
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/loader/Factory", CHECK_NULL);
-  KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
-
-  TempNewSymbol getClassLoader = SymbolTable::new_symbol("newClassLoader", CHECK_NULL);
-  JavaValue result(T_OBJECT);
-  JavaCalls::call_static(&result, klass, getClassLoader, vmSymbols::void_classloader_signature(), CHECK_NULL);
-  return (oop) result.get_jobject();
-}
-
 void GraalRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) {
   Thread* THREAD = Thread::current();
   CLEAR_PENDING_EXCEPTION;
--- a/src/share/vm/graal/graalRuntime.hpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/graal/graalRuntime.hpp	Sun Dec 07 20:43:33 2014 +0100
@@ -127,6 +127,11 @@
 
  public:
 
+  /**
+   * Ensures that the Graal class loader is initialized and the well known Graal classes are loaded.
+   */
+  static void ensure_graal_class_loader_is_initialized();
+
   static void initialize_natives(JNIEnv *env, jclass c2vmClass);
 
   static bool is_HotSpotGraalRuntime_initialized() { return _HotSpotGraalRuntime_initialized; }
@@ -200,11 +205,6 @@
    */
   static Klass* load_required_class(Symbol* name);
 
-  /**
-   * Creates a separate class loader for classes in graal.jar and graal-truffle.jar.
-   */
-  static oop compute_graal_class_loader(TRAPS);
-
   static BufferBlob* initialize_buffer_blob();
 
   /**
--- a/src/share/vm/prims/nativeLookup.cpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/prims/nativeLookup.cpp	Sun Dec 07 20:43:33 2014 +0100
@@ -127,6 +127,7 @@
   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
   void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
 #ifdef GRAAL
+  void     JNICALL JVM_InitGraalClassLoader(JNIEnv *env, jclass c, jobject loader);
   void     JNICALL JVM_InitializeGraalNatives(JNIEnv *env, jclass compilerToVMClass);
   jobject  JNICALL JVM_GetGraalRuntime(JNIEnv *env, jclass c);
   jobject  JNICALL JVM_GetGraalServiceImpls(JNIEnv *env, jclass c);
@@ -148,6 +149,7 @@
   { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
 #ifdef GRAAL
+  { CC"Java_com_oracle_graal_hotspot_loader_Factory_init",                                                NULL, FN_PTR(JVM_InitGraalClassLoader)               },
   { CC"Java_com_oracle_graal_api_runtime_Graal_initializeRuntime",                                        NULL, FN_PTR(JVM_GetGraalRuntime)                    },
   { CC"Java_com_oracle_graal_api_runtime_Services_getServiceImpls",                                       NULL, FN_PTR(JVM_GetGraalServiceImpls)               },
   { CC"Java_com_oracle_truffle_api_Truffle_createRuntime",                                                NULL, FN_PTR(JVM_CreateTruffleRuntime)               },
--- a/src/share/vm/runtime/thread.cpp	Fri Dec 05 11:09:57 2014 +0100
+++ b/src/share/vm/runtime/thread.cpp	Sun Dec 07 20:43:33 2014 +0100
@@ -1433,7 +1433,7 @@
 
 bool graal_counters_include(JavaThread* thread) {
   oop threadObj = thread->threadObj();
-  return !GraalCountersExcludeCompiler || (!thread->is_Compiler_thread() && (threadObj == NULL || threadObj->klass() != SystemDictionary::CompilerThread_klass()));
+  return !GraalCountersExcludeCompiler || !thread->is_Compiler_thread();
 }
 
 void JavaThread::collect_counters(typeArrayOop array) {
@@ -3686,11 +3686,6 @@
   // set_init_completed has just been called, causing exceptions not to be shortcut
   // anymore. We call vm_exit_during_initialization directly instead.
   SystemDictionary::compute_java_system_loader(THREAD);
-#ifdef GRAAL
-  if (!HAS_PENDING_EXCEPTION) {
-    SystemDictionary::initialize_preloaded_graal_classes(THREAD);
-  }
-#endif
   if (HAS_PENDING_EXCEPTION) {
     vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
   }