changeset 11838:16d0eb40d31c

Merge
author Gilles Duboscq <duboscq@ssw.jku.at>
date Mon, 30 Sep 2013 18:05:25 +0200
parents 4187b229d2ec (diff) bd3441f941f9 (current diff)
children 0e2cceed1caf
files graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java
diffstat 45 files changed, 2133 insertions(+), 254 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java	Mon Sep 30 18:05:25 2013 +0200
@@ -399,9 +399,11 @@
             }
             for (Method m : c.getDeclaredMethods()) {
                 if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) {
-                    Method overridden = vtable.methods.put(new NameAndSignature(m), m);
-                    if (overridden != null) {
-                        // println(m + " overrides " + overridden);
+                    if (isAbstract(m.getModifiers())) {
+                        // A subclass makes a concrete method in a superclass abstract
+                        vtable.methods.remove(new NameAndSignature(m));
+                    } else {
+                        vtable.methods.put(new NameAndSignature(m), m);
                     }
                 }
             }
@@ -438,7 +440,13 @@
     @Test
     public void resolveMethodTest() {
         for (Class c : classes) {
-            if (!c.isPrimitive() && !c.isInterface()) {
+            if (c.isInterface() || c.isPrimitive()) {
+                ResolvedJavaType type = runtime.lookupJavaType(c);
+                for (Method m : c.getDeclaredMethods()) {
+                    ResolvedJavaMethod impl = type.resolveMethod(runtime.lookupJavaMethod(m));
+                    assertEquals(m.toString(), null, impl);
+                }
+            } else {
                 ResolvedJavaType type = runtime.lookupJavaType(c);
                 VTable vtable = getVTable(c);
                 for (Method impl : vtable.methods.values()) {
@@ -449,6 +457,11 @@
                         checkResolveMethod(type, m, i);
                     }
                 }
+                for (Method m : c.getDeclaredMethods()) {
+                    ResolvedJavaMethod impl = type.resolveMethod(runtime.lookupJavaMethod(m));
+                    ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl;
+                    assertEquals(type + " " + m.toString(), expected, impl);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java	Mon Sep 30 18:05:25 2013 +0200
@@ -50,17 +50,21 @@
     boolean isSynthetic();
 
     /**
-     * Gets the constant value of this field for a given object, if available.
+     * Gets the constant value of this field. Note that a {@code static final} field may not be
+     * considered constant if its declaring class is not yet initialized or if it is a well known
+     * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}).
      * 
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
-     * @return the constant value of this field or {@code null} if the constant value is not
-     *         available
+     * @return the constant value of this field or {@code null} if this field is not considered
+     *         constant by the runtime
      */
     Constant readConstantValue(Constant receiver);
 
     /**
-     * Gets the current value of this field for a given object, if available.
+     * Gets the current value of this field for a given object, if available. There is no guarantee
+     * that the same value will be returned by this method for a field unless the field is
+     * considered to be {@link #readConstantValue(Constant)} by the runtime.
      * 
      * @param receiver object from which this field's value is to be read. This value is ignored if
      *            this field is static.
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Mon Sep 30 18:05:25 2013 +0200
@@ -205,10 +205,13 @@
 
     /**
      * Resolves the method implementation for virtual dispatches on objects of this dynamic type.
+     * This resolution process only searches "up" the class hierarchy of this type. A broader search
+     * that also walks "down" the hierarchy is implemented by
+     * {@link #findUniqueConcreteMethod(ResolvedJavaMethod)}.
      * 
      * @param method the method to select the implementation of
-     * @return the method implementation that would be selected at runtime, or {@code null} if the
-     *         runtime cannot resolve the method at this point in time.
+     * @return the concrete method that would be selected at runtime, or {@code null} if there is no
+     *         concrete implementation of {@code method} in this type or any of its superclasses
      */
     ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method);
 
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon Sep 30 18:05:25 2013 +0200
@@ -747,7 +747,7 @@
         emitOperandHelper(0, dst);
     }
 
-    private void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) {
+    public void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) {
         int shortSize = 2;
         int longSize = 6;
         long disp = jumpTarget - codeBuffer.position();
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Mon Sep 30 18:05:25 2013 +0200
@@ -288,7 +288,13 @@
         }
 
         public String emitVariable(Variable v) {
-            return (" %r" + v.index);
+            String name = v.getName();
+
+            if (name == null) {
+                return (" %r" + v.index);
+            } else {
+                return name;
+            }
         }
     }
 
@@ -757,6 +763,6 @@
 
     @Override
     public PTXAddress getPlaceholder() {
-        throw GraalInternalError.unimplemented("PTXAddress.getPlaceholder()");
+        return null;
     }
 }
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayPTXTest.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayPTXTest.java	Mon Sep 30 18:05:25 2013 +0200
@@ -22,96 +22,59 @@
  */
 package com.oracle.graal.compiler.ptx.test;
 
-import java.lang.reflect.Method;
+import static com.oracle.graal.lir.ptx.ThreadDimension.*;
 
-import org.junit.*;
+import com.oracle.graal.lir.ptx.ParallelOver;
+import com.oracle.graal.lir.ptx.Warp;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import org.junit.Test;
 
 public class ArrayPTXTest extends PTXTestBase {
 
-    @Ignore
     @Test
     public void testArray() {
-        int[] arrayI = {
-            1, 2, 3, 4, 5
+        int[] array1 = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9
+        };
+        int[] array2 = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9
+        };
+        int[] array3 = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9
         };
-        Integer resI = (Integer) invoke(compile("testArray1I"), arrayI, 3);
-        printReport("testArray1I: " + resI);
-        // compile("testArray1J");
-        // compile("testArray1B");
-        // compile("testArray1S");
-        // compile("testArray1C");
-        // compile("testArray1F");
-        // compile("testArray1D");
-        // compile("testArray1L");
-        // compile("testStoreArray1I");
-        // compile("testStoreArray1J");
-        // compile("testStoreArray1B");
-        // compile("testStoreArray1S");
-        // compile("testStoreArray1F");
-        // compile("testStoreArray1D");
-    }
+
+        invoke(compile("testStoreArray1I"), array1, 2);
+        printReport("testStoreArray1I: " + Arrays.toString(array1));
 
-    public static int testArray1I(int[] array, int i) {
-        return array[i];
-    }
+        invoke(compile("testStoreArrayWarp0"), array2, 2);
+        printReport("testStoreArrayWarp0: " + Arrays.toString(array2));
 
-    public static long testArray1J(long[] array, int i) {
-        return array[i];
-    }
+        invoke(compile("testStoreArrayWarp1I"), array3, 2);
+        printReport("testStoreArrayWarp1I: " + Arrays.toString(array3));
 
-    public static byte testArray1B(byte[] array, int i) {
-        return array[i];
-    }
-
-    public static short testArray1S(short[] array, int i) {
-        return array[i];
     }
 
-    public static char testArray1C(char[] array, int i) {
-        return array[i];
-    }
-
-    public static float testArray1F(float[] array, int i) {
-        return array[i];
-    }
-
-    public static double testArray1D(double[] array, int i) {
-        return array[i];
-    }
-
-    public static Object testArray1L(Object[] array, int i) {
-        return array[i];
-    }
-
-    public static void testStoreArray1I(int[] array, int i, int val) {
-        array[i] = val;
+    public static void testStoreArray1I(int[] array, int i) {
+        array[i] = 42;
     }
 
-    public static void testStoreArray1B(byte[] array, int i, byte val) {
-        array[i] = val;
-    }
-
-    public static void testStoreArray1S(short[] array, int i, short val) {
-        array[i] = val;
+    public static void testStoreArrayWarp0(int[] array,
+                                           @Warp(dimension = X) int i) {
+        array[i] = 42;
     }
 
-    public static void testStoreArray1J(long[] array, int i, long val) {
-        array[i] = val;
+    public static void testStoreArrayWarp1I(@ParallelOver(dimension = X) int[] array,
+                                            @Warp(dimension = X) int i) {
+        array[i] = 42;
     }
 
-    public static void testStoreArray1F(float[] array, int i, float val) {
-        array[i] = val;
-    }
-
-    public static void testStoreArray1D(double[] array, int i, double val) {
-        array[i] = val;
-    }
 
     public static void printReport(String message) {
         // CheckStyle: stop system..print check
         System.out.println(message);
         // CheckStyle: resume system..print check
-
     }
 
     public static void main(String[] args) {
--- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java	Mon Sep 30 18:05:25 2013 +0200
@@ -32,11 +32,13 @@
 import com.oracle.graal.compiler.ptx.PTXBackend;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.debug.Debug;
+import com.oracle.graal.hotspot.meta.HotSpotNmethod;
 import com.oracle.graal.hotspot.meta.HotSpotRuntime;
 import com.oracle.graal.hotspot.meta.HotSpotResolvedJavaMethod;
 import com.oracle.graal.hotspot.ptx.PTXHotSpotRuntime;
 import com.oracle.graal.java.GraphBuilderConfiguration;
 import com.oracle.graal.java.GraphBuilderPhase;
+import com.oracle.graal.lir.ptx.ParallelOver;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.spi.GraalCodeCacheProvider;
 import com.oracle.graal.phases.OptimisticOptimizations;
@@ -44,6 +46,8 @@
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.ptx.PTX;
+
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Modifier;
 
 public abstract class PTXTestBase extends GraalCompilerTest {
@@ -102,8 +106,42 @@
             boolean isStatic = Modifier.isStatic(compiledMethod.getModifiers());
             Object[] executeArgs = argsWithReceiver((isStatic ? null : this), args);
             HotSpotRuntime hsr = (HotSpotRuntime) runtime;
-            InstalledCode installedCode = hsr.addExternalMethod(sg.method(), result, sg);
-            Object r = installedCode.executeVarargs(executeArgs);
+            InstalledCode installedCode = hsr.addExternalMethod(compiledMethod, result, sg);
+            Annotation[][] params = compiledMethod.getParameterAnnotations();
+
+            int dimensionX = 1;
+            int dimensionY = 1;
+            int dimensionZ = 1;
+
+            for (int p = 0; p < params.length; p++) {
+                Annotation[] annos = params[p];
+                if (annos != null) {
+                    for (int a = 0; a < annos.length; a++) {
+                        Annotation aa = annos[a];
+                        if (args[p] instanceof int[] && aa.annotationType().equals(ParallelOver.class)) {
+                            int[] iarray = (int[]) args[p];
+                            ParallelOver threadBlockDimension = (ParallelOver) aa;
+                            switch (threadBlockDimension.dimension()) {
+                                case X:
+                                    dimensionX = iarray.length;
+                                    break;
+                                case Y:
+                                    dimensionY = iarray.length;
+                                    break;
+                                case Z:
+                                    dimensionZ = iarray.length;
+                                    break;
+                            }
+                        }
+                    }
+                }
+            }
+            Object r;
+            if (dimensionX != 1 || dimensionY != 1 || dimensionZ != 1) {
+                r = ((HotSpotNmethod) installedCode).executeParallel(dimensionX, dimensionY, dimensionZ, executeArgs);
+            } else {
+                r = installedCode.executeVarargs(executeArgs);
+            }
             return r;
         } catch (Throwable th) {
             th.printStackTrace();
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Sep 30 18:05:25 2013 +0200
@@ -62,6 +62,9 @@
 import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.java.*;
 
+import java.lang.annotation.*;
+
+
 /**
  * This class implements the PTX specific portion of the LIR generator.
  */
@@ -120,7 +123,9 @@
             if (isRegister(value)) {
                 return asRegister(value).asValue(value.getKind().getStackKind());
             } else if (isStackSlot(value)) {
-                return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize());
+                return StackSlot.get(value.getKind().getStackKind(),
+                                     asStackSlot(value).getRawOffset(),
+                                     asStackSlot(value).getRawAddFrameSize());
             } else {
                 throw GraalInternalError.shouldNotReachHere();
             }
@@ -132,22 +137,62 @@
     public void emitPrologue() {
         // Need to emit .param directives based on incoming arguments and return value
         CallingConvention incomingArguments = cc;
-        int argCount = incomingArguments.getArgumentCount();
-        // Additional argument for return value.
-        Variable[] params = new Variable[argCount + 1];
-        for (int i = 0; i < argCount; i++) {
-            params[i] = (Variable) incomingArguments.getArgument(i);
+        Object returnObject = incomingArguments.getReturn();
+        AllocatableValue[] params;
+        int argCount;
+
+        if (returnObject == Value.ILLEGAL) {
+            params = incomingArguments.getArguments();
+        } else {
+            argCount = incomingArguments.getArgumentCount();
+            params = new Variable[argCount + 1];
+            for (int i = 0; i < argCount; i++) {
+                params[i] = incomingArguments.getArgument(i);
+            }
+            params[argCount] = (Variable) returnObject;
         }
-        // Add the return value as the last parameter.
-        params[argCount] = (Variable) incomingArguments.getReturn();
 
         append(new PTXParameterOp(params));
         for (LocalNode local : graph.getNodes(LocalNode.class)) {
             Value param = params[local.index()];
-            setResult(local, emitLoadParam(param.getKind(), param, null));
+            Annotation[] annos = graph.method().getParameterAnnotations()[local.index()];
+            Warp warpAnnotation = null;
+
+            if (annos != null) {
+                for (int a = 0; a < annos.length; a++) {
+                    if (annos[a].annotationType().equals(Warp.class)) {
+                        warpAnnotation = (Warp) annos[a];
+                    }
+                }
+            }
+            if (warpAnnotation != null) {
+                setResult(local, emitWarpParam(param.getKind(), warpAnnotation));
+            } else {
+                setResult(local, emitLoadParam(param.getKind(), param, null));
+            }
         }
     }
 
+    public Variable emitWarpParam(Kind kind, Warp annotation) {
+        Variable result = newVariable(kind);
+        Variable tid = newVariable(Kind.Char);
+
+        switch (annotation.dimension()) {
+            case X:
+                tid.setName("%tid.x");
+                break;
+            case Y:
+                tid.setName("%tid.y");
+                break;
+            case Z:
+                tid.setName("%tid.y");
+                break;
+        }
+        emitMove(result, tid);
+
+        return result;
+    }
+
     @Override
     public Variable emitMove(Value input) {
         Variable result = newVariable(input.getKind());
@@ -168,39 +213,47 @@
     public PTXAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
+
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
                 baseRegister = Value.ILLEGAL;
-            } else if (asConstant(base).getKind() != Kind.Object) {
+            } else if (asConstant(base).getKind() != Kind.Object && !runtime.needsDataPatch(asConstant(base))) {
                 finalDisp += asConstant(base).asLong();
                 baseRegister = Value.ILLEGAL;
             } else {
                 baseRegister = load(base);
             }
+        } else if (base.equals(Value.ILLEGAL)) {
+            baseRegister = Value.ILLEGAL;
         } else {
             baseRegister = asAllocatable(base);
         }
 
-        @SuppressWarnings("unused")
-        Value indexRegister;
-        if (!index.equals(Value.ILLEGAL) && scale != 0) {
+        if (!index.equals(Value.ILLEGAL)) {
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
-                indexRegister = Value.ILLEGAL;
             } else {
+                Value convertedIndex;
+                Value indexRegister;
+
+                convertedIndex = emitConvert(Op.I2L, index);
                 if (scale != 1) {
-                    Variable longIndex = emitConvert(Op.I2L, index);
                     if (CodeUtil.isPowerOf2(scale)) {
-                        indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale)));
+                        indexRegister = emitShl(convertedIndex, Constant.forInt(CodeUtil.log2(scale)));
                     } else {
-                        indexRegister = emitMul(longIndex, Constant.forLong(scale));
+                        indexRegister = emitMul(convertedIndex, Constant.forInt(scale));
                     }
                 } else {
-                    indexRegister = asAllocatable(index);
+                    indexRegister = convertedIndex;
+                }
+                if (baseRegister.equals(Value.ILLEGAL)) {
+                    baseRegister = asAllocatable(indexRegister);
+                } else {
+                    Variable longBaseRegister = newVariable(Kind.Long);
+                    emitMove(longBaseRegister, baseRegister);
+                    baseRegister = emitAdd(longBaseRegister, indexRegister);
                 }
             }
-        } else {
-            indexRegister = Value.ILLEGAL;
         }
 
         return new PTXAddressValue(target().wordKind, baseRegister, finalDisp);
@@ -287,6 +340,7 @@
         throw GraalInternalError.unimplemented("PTXLIRGenerator.emitConditionalMove()");
     }
 
+
     @Override
     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
         throw new InternalError("NYI");
@@ -504,7 +558,7 @@
                 append(new Op2Stack(ISHL, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op1Stack(LSHL, result, loadNonConst(b)));
+                append(new Op2Stack(LSHL, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -520,7 +574,7 @@
                 append(new Op2Stack(ISHR, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op1Stack(LSHR, result, loadNonConst(b)));
+                append(new Op2Stack(LSHR, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon Sep 30 18:05:25 2013 +0200
@@ -447,7 +447,7 @@
     @Test
     public void testLoop4() {
         SchedulePhase schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL);
-        assertReadWithinStartBlock(schedule, true);
+        assertReadWithinStartBlock(schedule, false);
         assertReadWithinReturnBlock(schedule, false);
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Mon Sep 30 18:05:25 2013 +0200
@@ -236,11 +236,10 @@
         FrameMap frameMap = tasm.frameMap;
         RegisterConfig regConfig = frameMap.registerConfig;
         HotSpotVMConfig config = runtime().config;
-        Label unverifiedStub = installedCodeOwner == null || isStatic(installedCodeOwner.getModifiers()) ? null : new Label();
+        Label verifiedStub = new Label();
 
         // Emit the prefix
-
-        if (unverifiedStub != null) {
+        if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
             tasm.recordMark(Marks.MARK_UNVERIFIED_ENTRY);
             CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{runtime().lookupJavaType(Object.class)}, target, false);
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
@@ -257,11 +256,12 @@
             } else {
                 asm.cmpq(inlineCacheKlass, src);
             }
-            asm.jcc(ConditionFlag.NotEqual, unverifiedStub);
+            AMD64Call.directConditionalJmp(tasm, asm, runtime().lookupForeignCall(IC_MISS_HANDLER), ConditionFlag.NotEqual);
         }
 
         asm.align(config.codeEntryAlignment);
         tasm.recordMark(Marks.MARK_OSR_ENTRY);
+        asm.bind(verifiedStub);
         tasm.recordMark(Marks.MARK_VERIFIED_ENTRY);
 
         // Emit code for the LIR
@@ -278,10 +278,5 @@
             // it has no calls that can cause such "return" entries
             assert !frameMap.accessesCallerFrame() : lirGen.getGraph();
         }
-
-        if (unverifiedStub != null) {
-            asm.bind(unverifiedStub);
-            AMD64Call.directJmp(tasm, asm, runtime().lookupForeignCall(IC_MISS_HANDLER));
-        }
     }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Mon Sep 30 18:05:25 2013 +0200
@@ -60,30 +60,42 @@
     }
 
     @Test
-    public void testAESEncryptSubstitution() throws Exception {
+    public void testEncryptSubstitution() throws Exception {
         byte[] seed = {0x4, 0x7, 0x1, 0x1};
         SecureRandom random = new SecureRandom(seed);
         KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
+        KeyGenerator desKeyGen = KeyGenerator.getInstance("DESede");
         aesKeyGen.init(128, random);
+        desKeyGen.init(168, random);
         SecretKey aesKey = aesKeyGen.generateKey();
+        SecretKey desKey = desKeyGen.generateKey();
         byte[] input = readClassfile16(getClass());
 
-        ByteArrayOutputStream expected = new ByteArrayOutputStream();
-        expected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
-        expected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
+        ByteArrayOutputStream aesExpected = new ByteArrayOutputStream();
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
 
         if (compiledAndInstall("com.sun.crypto.provider.AESCrypt", "encryptBlock", "decryptBlock")) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
-            Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+            Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
         }
 
+        ByteArrayOutputStream desExpected = new ByteArrayOutputStream();
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input));
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input));
+
         if (compiledAndInstall("com.sun.crypto.provider.CipherBlockChaining", "encrypt", "decrypt")) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
-            Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+            Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
+
+            actual.reset();
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input));
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input));
+            Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray());
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon Sep 30 18:05:25 2013 +0200
@@ -128,8 +128,7 @@
             CompilationStatistics stats = CompilationStatistics.create(method, entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI);
             final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
             if (printCompilation) {
-                TTY.println(String.format("%-6d Graal %-70s %-45s %-50s %s...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature(),
-                                entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") "));
+                TTY.println(getMethodDescription() + "...");
             }
             if (HotSpotPrintCompilation.getValue()) {
                 printCompilation();
@@ -161,7 +160,10 @@
                 });
             } finally {
                 filter.remove();
-                if (printCompilation) {
+                final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
+                if (printAfterCompilation) {
+                    TTY.println(getMethodDescription() + String.format(" | %4dms %5dB", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1)));
+                } else if (printCompilation) {
                     TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1)));
                 }
             }
@@ -193,6 +195,11 @@
         }
     }
 
+    private String getMethodDescription() {
+        return String.format("%-6d Graal %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().getMethodDescriptor(),
+                        entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") ");
+    }
+
     /**
      * Print a HotSpot-style compilation message to the console.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java	Mon Sep 30 18:05:25 2013 +0200
@@ -55,4 +55,7 @@
     long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException;
 
     Object executeExternalMethodVarargs(Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
+
+    Object executeParallelMethodVarargs(int dimX, int dimY, int dimZ,
+                                        Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java	Mon Sep 30 18:05:25 2013 +0200
@@ -39,4 +39,7 @@
     public native boolean deviceDetach();
 
     public native Object executeExternalMethodVarargs(Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
+
+    public native Object executeParallelMethodVarargs(int dimX, int dimY, int dimZ,
+                                                      Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java	Mon Sep 30 18:05:25 2013 +0200
@@ -123,6 +123,15 @@
         return true;
     }
 
+    public Object executeParallel(int dimX, int dimY, int dimZ, Object... args) throws InvalidInstalledCodeException {
+        assert checkArgs(args);
+
+        assert isExternal(); // for now
+
+        return graalRuntime().getCompilerToGPU().executeParallelMethodVarargs(dimX, dimY, dimZ, args, this);
+
+    }
+
     @Override
     public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
         assert checkArgs(args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Mon Sep 30 18:05:25 2013 +0200
@@ -169,6 +169,12 @@
 
     private static final String SystemClassName = "Ljava/lang/System;";
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * The {@code value} field in {@link OptionValue} is considered constant if the type of
+     * {@code receiver} is (assignable to) {@link StableOptionValue}.
+     */
     @Override
     public Constant readConstantValue(Constant receiver) {
         assert !AOTCompilation.getValue() || isCalledForSnippets() : receiver;
@@ -198,6 +204,7 @@
             } else {
                 Class<?> clazz = object.getClass();
                 if (StableOptionValue.class.isAssignableFrom(clazz)) {
+                    assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this;
                     StableOptionValue<?> option = (StableOptionValue<?>) object;
                     return Constant.forObject(option.getValue());
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Mon Sep 30 18:05:25 2013 +0200
@@ -345,7 +345,11 @@
     @Override
     public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method) {
         assert method instanceof HotSpotMethod;
-        return (ResolvedJavaMethod) graalRuntime().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
+        ResolvedJavaMethod res = (ResolvedJavaMethod) graalRuntime().getCompilerToVM().resolveMethod(this, method.getName(), ((HotSpotSignature) method.getSignature()).getMethodDescriptor());
+        if (res == null || isAbstract(res.getModifiers())) {
+            return null;
+        }
+        return res;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Sep 30 18:05:25 2013 +0200
@@ -49,6 +49,7 @@
 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
+import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.Log.*;
@@ -994,10 +995,15 @@
     private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
         StructuredGraph g = n.graph();
         ValueNode array = n.array();
-        Stamp stamp = StampFactory.positiveInt();
-        ReadNode arrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, g), stamp, BarrierType.NONE, false));
-        g.addBeforeFixed(n, arrayLength);
-        tool.createNullCheckGuard(arrayLength, array);
+        ValueNode arrayLength = readArrayLength(array, tool.getRuntime());
+        if (arrayLength == null) {
+            Stamp stamp = StampFactory.positiveInt();
+            ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, g), stamp, BarrierType.NONE, false));
+            g.addBeforeFixed(n, readArrayLength);
+            tool.createNullCheckGuard(readArrayLength, array);
+            arrayLength = readArrayLength;
+        }
+
         return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Mon Sep 30 18:05:25 2013 +0200
@@ -56,9 +56,12 @@
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
         Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false);
 
-        Pointer memory = Word.fromObject(result);
         for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) {
-            memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION);
+            /*
+             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
+             * to be copied atomically, but here they are copied as two 4-byte word values.
+             */
+            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
         }
 
         return result;
@@ -73,9 +76,12 @@
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
         Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false);
 
-        Pointer memory = Word.fromObject(result);
         for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
-            memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION);
+            /*
+             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
+             * to be copied atomically, but here they are copied as two 4-byte word values.
+             */
+            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
         }
         return result;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java	Mon Sep 30 18:05:25 2013 +0200
@@ -192,6 +192,11 @@
             }
         } else {
             for (long i = 0; i < byteLength; i += VECTOR_SIZE) {
+                /*
+                 * TODO atomicity problem on 32-bit architectures: The JVM spec requires double
+                 * values to be copied atomically, but not long values. For example, on Intel 32-bit
+                 * this code is not atomic as long as the vector kind remains Kind.Long.
+                 */
                 Long a = UnsafeLoadNode.load(src, arrayBaseOffset, i + srcOffset, VECTOR_KIND);
                 UnsafeStoreNode.store(dest, arrayBaseOffset, i + destOffset, a.longValue(), VECTOR_KIND);
             }
@@ -225,22 +230,22 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
 
-        Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize);
-        Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize);
-        Word destStart = destOffset;
-        long sizeInBytes = ((long) length) << log2ElementSize;
-        Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize));
+        Unsigned srcOffset = Word.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned destOffset = Word.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned destStart = destOffset;
+        Unsigned sizeInBytes = Word.unsigned(length).shiftLeft(log2ElementSize);
+        Unsigned destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize));
 
-        int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE);
-        Word destNonVectorEnd = destStart.add(nonVectorBytes);
+        Unsigned nonVectorBytes = sizeInBytes.unsignedRemainder(Word.unsigned(VECTOR_SIZE));
+        Unsigned destNonVectorEnd = destStart.add(nonVectorBytes);
 
         while (destOffset.belowThan(destNonVectorEnd)) {
-            destOffset.writeByte(0, srcOffset.readByte(0, ANY_LOCATION), ANY_LOCATION);
+            ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION);
             destOffset = destOffset.add(1);
             srcOffset = srcOffset.add(1);
         }
         while (destOffset.belowThan(destEnd)) {
-            destOffset.writeWord(0, srcOffset.readWord(0, ANY_LOCATION), ANY_LOCATION);
+            ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, ANY_LOCATION), ANY_LOCATION);
             destOffset = destOffset.add(wordSize());
             srcOffset = srcOffset.add(wordSize());
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java	Mon Sep 30 18:05:25 2013 +0200
@@ -49,18 +49,16 @@
 public class WriteBarrierSnippets implements Snippets {
 
     private static final SnippetCounter.Group countersWriteBarriers = SnippetCounters.getValue() ? new SnippetCounter.Group("WriteBarriers") : null;
-    private static final SnippetCounter serialFieldWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialFieldWriteBarrier", "Number of Serial Field Write Barriers");
-    private static final SnippetCounter serialArrayWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialArrayWriteBarrier", "Number of Serial Array Write Barriers");
-    private static final SnippetCounter g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrierCounter",
-                    "Number of attempted G1 Post Write Barriers");
-    private static final SnippetCounter g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrierCounter", "Number of G1 attempted Pre Write Barriers");
-    private static final SnippetCounter g1AttemptedRefFieldBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedRefFieldBarrierCounter",
-                    "Number of G1 attempted Ref Field Read Barriers");
-    private static final SnippetCounter g1EffectivePostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePostWriteBarrierCounter",
-                    "Number of effective G1 Post Write Barriers");
-    private static final SnippetCounter g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrierCounter", "Number of G1 effective Pre Write Barriers");
-    private static final SnippetCounter g1EffectiveRefFieldBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveRefFieldBarrierCounter",
-                    "Number of G1 effective Ref Field Read Barriers");
+    private static final SnippetCounter serialWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialWriteBarrier", "Number of Serial Write Barriers");
+    private static final SnippetCounter g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrier", "Number of G1 attempted Pre Write Barriers");
+    private static final SnippetCounter g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrier", "Number of G1 effective Pre Write Barriers");
+    private static final SnippetCounter g1ExecutedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPreWriteBarrier", "Number of G1 executed Pre Write Barriers");
+    private static final SnippetCounter g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrier", "Number of attempted G1 Post Write Barriers");
+    private static final SnippetCounter g1EffectiveAfterXORPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterXORPostWriteBarrier",
+                    "Number of effective G1 Post Write Barriers (after passing the XOR test)");
+    private static final SnippetCounter g1EffectiveAfterNullPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterNullPostWriteBarrier",
+                    "Number of effective G1 Post Write Barriers (after passing the NULL test)");
+    private static final SnippetCounter g1ExecutedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPostWriteBarrier", "Number of executed G1 Post Write Barriers");
 
     public static final LocationIdentity GC_CARD_LOCATION = new NamedLocationIdentity("GC-Card");
     public static final LocationIdentity GC_LOG_LOCATION = new NamedLocationIdentity("GC-Log");
@@ -76,11 +74,10 @@
         Pointer oop;
         if (usePrecise) {
             oop = Word.fromArray(fixedObject, location);
-            serialArrayWriteBarrierCounter.inc();
         } else {
             oop = Word.fromObject(fixedObject);
-            serialFieldWriteBarrierCounter.inc();
         }
+        serialWriteBarrierCounter.inc();
         Word base = (Word) oop.unsignedShiftRight(cardTableShift());
         long startAddress = cardTableStart();
         int displacement = 0;
@@ -136,8 +133,9 @@
             log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue);
             log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L);
         }
+        g1AttemptedPreWriteBarrierCounter.inc();
         // If the concurrent marker is enabled, the barrier is issued.
-        if (probability(NOT_LIKELY_PROBABILITY, markingValue != (byte) 0)) {
+        if (probability(NOT_FREQUENT_PROBABILITY, markingValue != (byte) 0)) {
             // If the previous value has to be loaded (before the write), the load is issued.
             // The load is always issued except the cases of CAS and referent field.
             if (probability(LIKELY_PROBABILITY, doLoad)) {
@@ -146,17 +144,11 @@
                     log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue());
                     verifyOop(previousOop.toObject());
                 }
-                g1AttemptedPreWriteBarrierCounter.inc();
-            } else {
-                g1AttemptedRefFieldBarrierCounter.inc();
             }
+            g1EffectivePreWriteBarrierCounter.inc();
             // If the previous value is null the barrier should not be issued.
             if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) {
-                if (doLoad) {
-                    g1EffectivePreWriteBarrierCounter.inc();
-                } else {
-                    g1EffectiveRefFieldBarrierCounter.inc();
-                }
+                g1ExecutedPreWriteBarrierCounter.inc();
                 // If the thread-local SATB buffer is full issue a native call which will
                 // initialize a new one and add the entry.
                 if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
@@ -217,15 +209,20 @@
         Word cardAddress = cardBase.add(displacement);
 
         g1AttemptedPostWriteBarrierCounter.inc();
-        if (probability(LIKELY_PROBABILITY, xorResult.notEqual(0))) {
+        if (probability(FREQUENT_PROBABILITY, xorResult.notEqual(0))) {
+            g1EffectiveAfterXORPostWriteBarrierCounter.inc();
+
             // If the written value is not null continue with the barrier addition.
             if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) {
                 byte cardByte = cardAddress.readByte(0);
+                g1EffectiveAfterNullPostWriteBarrierCounter.inc();
+
                 // If the card is already dirty, (hence already enqueued) skip the insertion.
-                if (probability(LIKELY_PROBABILITY, cardByte != (byte) 0)) {
-                    g1EffectivePostWriteBarrierCounter.inc();
+                if (probability(NOT_FREQUENT_PROBABILITY, cardByte != (byte) 0)) {
                     log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), Word.unsigned(cardByte).rawValue());
                     cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
+                    g1ExecutedPostWriteBarrierCounter.inc();
+
                     // If the thread local card queue is full, issue a native call which will
                     // initialize a new one and add the card entry.
                     if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/ArrayCopyGeneric.java	Mon Sep 30 18:05:25 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011, 2012, 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.jtt.optimize;
+
+import com.oracle.graal.jtt.*;
+
+import org.junit.*;
+
+/*
+ * Tests calls to the array copy method.
+ */
+public class ArrayCopyGeneric extends JTTTest {
+
+    public Object[] arraysFrom;
+    public Object[] arraysTo;
+
+    public void init() {
+        arraysFrom = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
+                        new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
+        arraysTo = new Object[]{new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new short[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
+                        new long[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new float[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
+    }
+
+    public Object test() {
+        init();
+
+        for (int i = 0; i < arraysFrom.length; i++) {
+            Object from = arraysFrom[i];
+            Object to = arraysTo[i];
+            System.arraycopy(from, 1, to, 2, 2);
+            System.arraycopy(from, 8, to, 7, 2);
+        }
+        return arraysTo;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test");
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon Sep 30 18:05:25 2013 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.spi.*;
@@ -182,6 +183,14 @@
         masm.ensureUniquePC();
     }
 
+    public static void directConditionalJmp(TargetMethodAssembler tasm, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) {
+        int before = masm.codeBuffer.position();
+        masm.jcc(cond, 0, true);
+        int after = masm.codeBuffer.position();
+        tasm.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
     public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
         int before = masm.codeBuffer.position();
         masm.call(dst);
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java	Mon Sep 30 18:05:25 2013 +0200
@@ -75,7 +75,7 @@
                 case D2I:
                 case D2L:
                 case D2F:
-                    break;  // cvt handles the move 
+                    break;  // cvt handles the move
                 default:
                     PTXMove.move(tasm, masm, result, x);
             }
@@ -422,11 +422,73 @@
     }
 
     private static void verifyKind(PTXArithmetic opcode, Value result, Value x, Value y) {
-        if (((opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int)
-            || (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long)
-            || (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float)
-            || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double)) == false) {
-                throw GraalInternalError.shouldNotReachHere("opcode: "  + opcode.name() + " x: " + x.getKind() + " y: " + y.getKind());
+        Kind rk;
+        Kind xk;
+        Kind yk;
+        Kind xsk;
+        Kind ysk;
+
+        switch (opcode) {
+            case IADD:
+            case ISUB:
+            case IMUL:
+            case IDIV:
+            case IREM:
+            case IAND:
+            case IOR:
+            case IXOR:
+            case ISHL:
+            case ISHR:
+            case IUSHR:
+                rk = result.getKind();
+                xsk = x.getKind().getStackKind();
+                ysk = y.getKind().getStackKind();
+                assert rk == Kind.Int && xsk == Kind.Int && ysk == Kind.Int;
+                break;
+            case LADD:
+            case LSUB:
+            case LMUL:
+            case LDIV:
+            case LREM:
+            case LAND:
+            case LOR:
+            case LXOR:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Long && xk == Kind.Long && yk == Kind.Long;
+                break;
+            case LSHL:
+            case LSHR:
+            case LUSHR:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Long && xk == Kind.Long && (yk == Kind.Int || yk == Kind.Long);
+                break;
+            case FADD:
+            case FSUB:
+            case FMUL:
+            case FDIV:
+            case FREM:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Float && xk == Kind.Float && yk == Kind.Float;
+                break;
+            case DADD:
+            case DSUB:
+            case DMUL:
+            case DDIV:
+            case DREM:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Double && xk == Kind.Double && yk == Kind.Double :
+                    "opcode=" + opcode + ", result kind=" + rk + ", x kind=" + xk + ", y kind=" + yk;
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere("missing: " + opcode);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/ParallelOver.java	Mon Sep 30 18:05:25 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013, 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.lir.ptx;
+
+import static com.oracle.graal.lir.ptx.ThreadDimension.*;
+
+import java.lang.annotation.*;
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface ParallelOver {
+
+    String value() default "";
+
+    ThreadDimension dimension() default X;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/ThreadDimension.java	Mon Sep 30 18:05:25 2013 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, 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.lir.ptx;
+
+public enum ThreadDimension {
+X,
+Y,
+Z
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/Warp.java	Mon Sep 30 18:05:25 2013 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, 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.lir.ptx;
+
+import static com.oracle.graal.lir.ptx.ThreadDimension.*;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface Warp {
+
+    String value() default "";
+
+    ThreadDimension dimension() default X;
+}
+
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java	Mon Sep 30 18:05:25 2013 +0200
@@ -38,6 +38,8 @@
      */
     public final int index;
 
+    private String name;
+
     /**
      * Creates a new variable.
      * 
@@ -50,9 +52,21 @@
         this.index = index;
     }
 
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
     @Override
     public String toString() {
-        return "v" + index + getKindSuffix();
+        if (name != null) {
+            return name;
+        } else {
+            return "v" + index + getKindSuffix();
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Mon Sep 30 18:05:25 2013 +0200
@@ -45,23 +45,36 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (array() instanceof ArrayLengthProvider) {
-            ValueNode length = ((ArrayLengthProvider) array()).length();
+        ValueNode length = readArrayLength(array(), tool.runtime());
+        if (length != null) {
+            return length;
+        }
+        return this;
+    }
+
+    /**
+     * Gets the length of an array if possible.
+     * 
+     * @param array an array
+     * @return a node representing the length of {@code array} or null if it is not available
+     */
+    public static ValueNode readArrayLength(ValueNode array, MetaAccessProvider runtime) {
+        if (array instanceof ArrayLengthProvider) {
+            ValueNode length = ((ArrayLengthProvider) array).length();
             if (length != null) {
                 return length;
             }
         }
-        MetaAccessProvider runtime = tool.runtime();
-        if (runtime != null && array().isConstant() && !array().isNullConstant()) {
-            Constant constantValue = array().asConstant();
+        if (runtime != null && array.isConstant() && !array.isNullConstant()) {
+            Constant constantValue = array.asConstant();
             if (constantValue != null && constantValue.isNonNull()) {
                 Integer constantLength = runtime.lookupArrayLength(constantValue);
                 if (constantLength != null) {
-                    return ConstantNode.forInt(constantLength, graph());
+                    return ConstantNode.forInt(constantLength, array.graph());
                 }
             }
         }
-        return this;
+        return null;
     }
 
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java	Mon Sep 30 18:05:25 2013 +0200
@@ -30,6 +30,10 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
+/**
+ * A phase suite that applies {@linkplain CanonicalizerPhase canonicalization} to a graph after all
+ * phases in the suite have been applied if any of the phases changed the graph.
+ */
 public class IncrementalCanonicalizerPhase<C extends PhaseContext> extends PhaseSuite<C> {
 
     private final CanonicalizerPhase canonicalizer;
@@ -58,6 +62,8 @@
         graph.stopTrackingInputChange();
         graph.stopTrackingUsagesDroppedZero();
 
-        canonicalizer.applyIncremental(graph, context, changedNodes, newNodesMark, false);
+        if (graph.getMark() != newNodesMark || !changedNodes.isEmpty()) {
+            canonicalizer.applyIncremental(graph, context, changedNodes, newNodesMark, false);
+        }
     }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Sep 30 18:05:25 2013 +0200
@@ -167,6 +167,8 @@
     @Option(help = "")
     public static final OptionValue<Boolean> PrintCompilation = new OptionValue<>(false);
     @Option(help = "")
+    public static final OptionValue<Boolean> PrintAfterCompilation = new OptionValue<>(false);
+    @Option(help = "")
     public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> PrintIRWithLIR = new OptionValue<>(false);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Mon Sep 30 18:05:25 2013 +0200
@@ -26,6 +26,9 @@
 
 import com.oracle.graal.nodes.*;
 
+/**
+ * A compiler phase that can apply an ordered collection of phases to a graph.
+ */
 public class PhaseSuite<C> extends BasePhase<C> {
 
     private final List<BasePhase<? super C>> phases;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Sep 30 18:05:25 2013 +0200
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013, 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.replacements.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
+import com.oracle.graal.word.*;
+
+/**
+ * Tests for the {@link Pointer} read and write operations.
+ */
+public class ObjectAccessTest extends GraalCompilerTest implements Snippets {
+
+    private static final LocationIdentity ID = new NamedLocationIdentity("ID");
+    private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object};
+    private final TargetDescription target;
+    private final ReplacementsImpl installer;
+
+    public ObjectAccessTest() {
+        target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget();
+        installer = new ReplacementsImpl(runtime, new Assumptions(false), target);
+    }
+
+    private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
+
+    @Override
+    protected StructuredGraph parse(Method m) {
+        ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+    }
+
+    @Test
+    public void testRead1() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "1"), kind, false, ID);
+        }
+    }
+
+    @Test
+    public void testRead2() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "2"), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testRead3() {
+        for (Kind kind : KINDS) {
+            assertRead(parse("read" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+        }
+    }
+
+    @Test
+    public void testWrite1() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "1"), kind, false, ID);
+        }
+    }
+
+    @Test
+    public void testWrite2() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "2"), kind, true, ID);
+        }
+    }
+
+    @Test
+    public void testWrite3() {
+        for (Kind kind : KINDS) {
+            assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationIdentity.ANY_LOCATION);
+        }
+    }
+
+    private static void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
+        ReadNode read = (ReadNode) graph.start().next();
+        Assert.assertEquals(kind.getStackKind(), read.kind());
+        Assert.assertEquals(graph.getLocal(0), read.object());
+
+        IndexedLocationNode location = (IndexedLocationNode) read.location();
+        Assert.assertEquals(kind, location.getValueKind());
+        Assert.assertEquals(locationIdentity, location.getLocationIdentity());
+        Assert.assertEquals(1, location.getIndexScaling());
+
+        if (indexConvert) {
+            ConvertNode convert = (ConvertNode) location.getIndex();
+            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(graph.getLocal(1), convert.value());
+        } else {
+            Assert.assertEquals(graph.getLocal(1), location.getIndex());
+        }
+
+        ReturnNode ret = (ReturnNode) read.next();
+        Assert.assertEquals(read, ret.result());
+    }
+
+    private static void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
+        WriteNode write = (WriteNode) graph.start().next();
+        Assert.assertEquals(graph.getLocal(2), write.value());
+        Assert.assertEquals(graph.getLocal(0), write.object());
+        Assert.assertEquals(Kind.Void, write.kind());
+        Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci);
+
+        IndexedLocationNode location = (IndexedLocationNode) write.location();
+        Assert.assertEquals(kind, location.getValueKind());
+        Assert.assertEquals(locationIdentity, location.getLocationIdentity());
+        Assert.assertEquals(1, location.getIndexScaling());
+
+        if (indexConvert) {
+            ConvertNode convert = (ConvertNode) location.getIndex();
+            Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode);
+            Assert.assertEquals(graph.getLocal(1), convert.value());
+        } else {
+            Assert.assertEquals(graph.getLocal(1), location.getIndex());
+        }
+
+        ReturnNode ret = (ReturnNode) write.next();
+        Assert.assertEquals(null, ret.result());
+    }
+
+    @Snippet
+    public static byte readByte1(Object o, int offset) {
+        return ObjectAccess.readByte(o, offset, ID);
+    }
+
+    @Snippet
+    public static byte readByte2(Object o, int offset) {
+        return ObjectAccess.readByte(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static byte readByte3(Object o, int offset) {
+        return ObjectAccess.readByte(o, offset);
+    }
+
+    @Snippet
+    public static void writeByte1(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeByte2(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeByte3(Object o, int offset, byte value) {
+        ObjectAccess.writeByte(o, offset, value);
+    }
+
+    @Snippet
+    public static char readChar1(Object o, int offset) {
+        return ObjectAccess.readChar(o, offset, ID);
+    }
+
+    @Snippet
+    public static char readChar2(Object o, int offset) {
+        return ObjectAccess.readChar(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static char readChar3(Object o, int offset) {
+        return ObjectAccess.readChar(o, offset);
+    }
+
+    @Snippet
+    public static void writeChar1(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeChar2(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeChar3(Object o, int offset, char value) {
+        ObjectAccess.writeChar(o, offset, value);
+    }
+
+    @Snippet
+    public static short readShort1(Object o, int offset) {
+        return ObjectAccess.readShort(o, offset, ID);
+    }
+
+    @Snippet
+    public static short readShort2(Object o, int offset) {
+        return ObjectAccess.readShort(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static short readShort3(Object o, int offset) {
+        return ObjectAccess.readShort(o, offset);
+    }
+
+    @Snippet
+    public static void writeShort1(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeShort2(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeShort3(Object o, int offset, short value) {
+        ObjectAccess.writeShort(o, offset, value);
+    }
+
+    @Snippet
+    public static int readInt1(Object o, int offset) {
+        return ObjectAccess.readInt(o, offset, ID);
+    }
+
+    @Snippet
+    public static int readInt2(Object o, int offset) {
+        return ObjectAccess.readInt(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static int readInt3(Object o, int offset) {
+        return ObjectAccess.readInt(o, offset);
+    }
+
+    @Snippet
+    public static void writeInt1(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeInt2(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeInt3(Object o, int offset, int value) {
+        ObjectAccess.writeInt(o, offset, value);
+    }
+
+    @Snippet
+    public static long readLong1(Object o, int offset) {
+        return ObjectAccess.readLong(o, offset, ID);
+    }
+
+    @Snippet
+    public static long readLong2(Object o, int offset) {
+        return ObjectAccess.readLong(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static long readLong3(Object o, int offset) {
+        return ObjectAccess.readLong(o, offset);
+    }
+
+    @Snippet
+    public static void writeLong1(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeLong2(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeLong3(Object o, int offset, long value) {
+        ObjectAccess.writeLong(o, offset, value);
+    }
+
+    @Snippet
+    public static float readFloat1(Object o, int offset) {
+        return ObjectAccess.readFloat(o, offset, ID);
+    }
+
+    @Snippet
+    public static float readFloat2(Object o, int offset) {
+        return ObjectAccess.readFloat(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static float readFloat3(Object o, int offset) {
+        return ObjectAccess.readFloat(o, offset);
+    }
+
+    @Snippet
+    public static void writeFloat1(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat2(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeFloat3(Object o, int offset, float value) {
+        ObjectAccess.writeFloat(o, offset, value);
+    }
+
+    @Snippet
+    public static double readDouble1(Object o, int offset) {
+        return ObjectAccess.readDouble(o, offset, ID);
+    }
+
+    @Snippet
+    public static double readDouble2(Object o, int offset) {
+        return ObjectAccess.readDouble(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static double readDouble3(Object o, int offset) {
+        return ObjectAccess.readDouble(o, offset);
+    }
+
+    @Snippet
+    public static void writeDouble1(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble2(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeDouble3(Object o, int offset, double value) {
+        ObjectAccess.writeDouble(o, offset, value);
+    }
+
+    @Snippet
+    public static Object readObject1(Object o, int offset) {
+        return ObjectAccess.readObject(o, offset, ID);
+    }
+
+    @Snippet
+    public static Object readObject2(Object o, int offset) {
+        return ObjectAccess.readObject(o, Word.signed(offset), ID);
+    }
+
+    @Snippet
+    public static Object readObject3(Object o, int offset) {
+        return ObjectAccess.readObject(o, offset);
+    }
+
+    @Snippet
+    public static void writeObject1(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, offset, value, ID);
+    }
+
+    @Snippet
+    public static void writeObject2(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, Word.signed(offset), value, ID);
+    }
+
+    @Snippet
+    public static void writeObject3(Object o, int offset, Object value) {
+        ObjectAccess.writeObject(o, offset, value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/ObjectAccess.java	Mon Sep 30 18:05:25 2013 +0200
@@ -0,0 +1,936 @@
+/*
+ * Copyright (c) 2013, 2013, 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.word;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.word.Word.Opcode;
+import com.oracle.graal.word.Word.Operation;
+
+/**
+ * Low-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for
+ * {@link Pointer}, these methods access the raw memory without any null checks, read- or write
+ * barriers.
+ */
+public final class ObjectAccess {
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read (see {@link LocationNode})
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write (see {@link LocationNode})
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native byte readByte(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native char readChar(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native short readShort(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native int readInt(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native long readLong(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native float readFloat(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native double readDouble(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Word readWord(Object object, int offset);
+
+    /**
+     * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    @Operation(opcode = Opcode.READ)
+    public static native Object readObject(Object object, int offset);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, WordBase offset, Object val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeByte(Object object, int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeChar(Object object, int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeShort(Object object, int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeInt(Object object, int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeLong(Object object, int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeFloat(Object object, int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeDouble(Object object, int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeWord(Object object, int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (object + offset)}. The offset is in bytes.
+     * 
+     * @param object the base object for the memory access
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    @Operation(opcode = Opcode.WRITE)
+    public static native void writeObject(Object object, int offset, Object val);
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Sep 30 18:05:25 2013 +0200
@@ -50,6 +50,7 @@
     protected final MetaAccessProvider metaAccess;
     protected final ResolvedJavaType wordBaseType;
     protected final ResolvedJavaType wordImplType;
+    protected final ResolvedJavaType objectAccessType;
     protected final Kind wordKind;
 
     public WordTypeRewriterPhase(MetaAccessProvider metaAccess, Kind wordKind) {
@@ -57,6 +58,7 @@
         this.wordKind = wordKind;
         this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
         this.wordImplType = metaAccess.lookupJavaType(Word.class);
+        this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class);
     }
 
     @Override
@@ -191,8 +193,11 @@
      */
     protected void rewriteInvoke(StructuredGraph graph, MethodCallTargetNode callTargetNode) {
         ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
-        if (!wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass())) {
-            /* Not a method defined on WordBase or a subclass / subinterface, so nothing to rewrite. */
+        if (!wordBaseType.isAssignableFrom(targetMethod.getDeclaringClass()) && !objectAccessType.equals(targetMethod.getDeclaringClass())) {
+            /*
+             * Not a method defined on WordBase or a subclass / subinterface, and not on
+             * ObjectAccess, so nothing to rewrite.
+             */
             return;
         }
 
@@ -252,7 +257,7 @@
             case WRITE:
             case INITIALIZE: {
                 assert arguments.size() == 3 || arguments.size() == 4;
-                Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass()));
+                Kind writeKind = asKind(targetMethod.getSignature().getParameterType(Modifier.isStatic(targetMethod.getModifiers()) ? 2 : 1, targetMethod.getDeclaringClass()));
                 LocationNode location;
                 if (arguments.size() == 3) {
                     location = makeLocation(graph, arguments.get(1), writeKind, LocationIdentity.ANY_LOCATION);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Sep 26 17:33:04 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Mon Sep 30 18:05:25 2013 +0200
@@ -102,6 +102,7 @@
      * 
      * @return the assigned source code section
      */
+    @CompilerDirectives.SlowPath
     public final SourceSection getEncapsulatingSourceSection() {
         if (sourceSection == null && getParent() != null) {
             return getParent().getEncapsulatingSourceSection();
--- a/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/cpu/x86/vm/graalCodeInstaller_x86.hpp	Mon Sep 30 18:05:25 2013 +0200
@@ -50,6 +50,9 @@
     // the inlined vtable stub contains a "call register" instruction
     assert(method != NULL, "only valid for virtual calls");
     return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset());
+  } else if (inst->is_cond_jump()) {
+    address pc = (address) (inst);
+    return pc_offset + (jint) (Assembler::locate_next_instruction(pc) - pc);
   } else {
     fatal("unsupported type of instruction for call site");
     return 0;
@@ -145,21 +148,30 @@
 }
 
 inline void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) {
+  address pc = (address) inst;
   if (inst->is_call()) {
     // NOTE: for call without a mov, the offset must fit a 32-bit immediate
     //       see also CompilerToVM.getMaxCallTargetOffset()
-    NativeCall* call = nativeCall_at((address) (inst));
+    NativeCall* call = nativeCall_at(pc);
     call->set_destination((address) foreign_call_destination);
     _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand);
   } else if (inst->is_mov_literal64()) {
-    NativeMovConstReg* mov = nativeMovConstReg_at((address) (inst));
+    NativeMovConstReg* mov = nativeMovConstReg_at(pc);
     mov->set_data((intptr_t) foreign_call_destination);
     _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand);
-  } else {
-    NativeJump* jump = nativeJump_at((address) (inst));
+  } else if (inst->is_jump()) {
+    NativeJump* jump = nativeJump_at(pc);
     jump->set_jump_destination((address) foreign_call_destination);
-    _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand);
+    _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand);
+  } else if (inst->is_cond_jump()) {
+    address old_dest = nativeGeneralJump_at(pc)->jump_destination();
+    address disp = Assembler::locate_operand(pc, Assembler::call32_operand);
+    *(jint*) disp += ((address) foreign_call_destination) - old_dest;
+    _instructions->relocate(pc, runtime_call_Relocation::spec(), Assembler::call32_operand);
+  } else {
+    fatal("unsupported relocation for foreign call");
   }
+
   TRACE_graal_3("relocating (foreign call)  at %p", inst);
 }
 
--- a/src/gpu/ptx/vm/gpu_ptx.cpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/gpu/ptx/vm/gpu_ptx.cpp	Mon Sep 30 18:05:25 2013 +0200
@@ -228,15 +228,20 @@
 }
 
 bool gpu::Ptx::execute_kernel(address kernel, PTXKernelArguments &ptxka, JavaValue &ret) {
+    return gpu::Ptx::execute_warp(1, 1, 1, kernel, ptxka, ret);
+}
+
+bool gpu::Ptx::execute_warp(int dimX, int dimY, int dimZ,
+                            address kernel, PTXKernelArguments &ptxka, JavaValue &ret) {
   // grid dimensionality
   unsigned int gridX = 1;
   unsigned int gridY = 1;
   unsigned int gridZ = 1;
 
   // thread dimensionality
-  unsigned int blockX = 1;
-  unsigned int blockY = 1;
-  unsigned int blockZ = 1;
+  unsigned int blockX = dimX;
+  unsigned int blockY = dimY;
+  unsigned int blockZ = dimZ;
 
   struct CUfunc_st* cu_function = (struct CUfunc_st*) kernel;
 
@@ -264,7 +269,7 @@
   }
 
   if (TraceGPUInteraction) {
-    tty->print_cr("[CUDA] Success: Kernel Launch");
+    tty->print_cr("[CUDA] Success: Kernel Launch: X: %d Y: %d Z: %d", blockX, blockY, blockZ);
   }
 
   status = _cuda_cu_ctx_synchronize();
@@ -282,7 +287,7 @@
   // Get the result. TODO: Move this code to get_return_oop()
   BasicType return_type = ptxka.get_ret_type();
   switch (return_type) {
-     case T_INT :
+     case T_INT:
        {
          int return_val;
          status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._return_value_ptr, T_INT_BYTE_SIZE);
@@ -293,7 +298,7 @@
          ret.set_jint(return_val);
        }
        break;
-     case T_LONG :
+     case T_LONG:
        {
          long return_val;
          status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._return_value_ptr, T_LONG_BYTE_SIZE);
@@ -304,10 +309,14 @@
          ret.set_jlong(return_val);
        }
        break;
+     case T_VOID:
+       break;
      default:
-       tty->print_cr("[CUDA] TODO *** Unhandled return type");
+       tty->print_cr("[CUDA] TODO *** Unhandled return type: %d", return_type);
   }
 
+  // handle post-invocation object and array arguemtn
+  ptxka.reiterate();
 
   // Free device memory allocated for result
   status = gpu::Ptx::_cuda_cu_memfree(ptxka._return_value_ptr);
--- a/src/gpu/ptx/vm/gpu_ptx.hpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/gpu/ptx/vm/gpu_ptx.hpp	Mon Sep 30 18:05:25 2013 +0200
@@ -74,6 +74,7 @@
   static bool probe_linkage();
   static bool initialize_gpu();
   static void * generate_kernel(unsigned char *code, int code_len, const char *name);
+  static bool execute_warp(int dimX, int dimY, int dimZ, address kernel, PTXKernelArguments & ka, JavaValue &ret);
   static bool execute_kernel(address kernel, PTXKernelArguments & ka, JavaValue &ret);
 public:
 #if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64)
--- a/src/gpu/ptx/vm/ptxKernelArguments.cpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/gpu/ptx/vm/ptxKernelArguments.cpp	Mon Sep 30 18:05:25 2013 +0200
@@ -32,12 +32,18 @@
 // Get next java argument
 oop PTXKernelArguments::next_arg(BasicType expectedType) {
   assert(_index < _args->length(), "out of bounds");
-  oop arg=((objArrayOop) (_args))->obj_at(_index++);
-  assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch");
+
+  oop arg = ((objArrayOop) (_args))->obj_at(_index++);
+  assert(expectedType == T_OBJECT ||
+         java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch");
+
   return arg;
 }
 
-void PTXKernelArguments::do_int()    {
+void PTXKernelArguments::do_int() {
+  if (is_after_invocation()) {
+    return;
+  }
   // If the parameter is a return value,
   if (is_return_type()) {
     // Allocate device memory for T_INT return value pointer on device. Size in bytes
@@ -50,8 +56,7 @@
     // Push _return_value_ptr to _kernelBuffer
     *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
     _bufferOffset += sizeof(_return_value_ptr);
-  }
-  else {
+  } else {
     // Get the next java argument and its value which should be a T_INT
     oop arg = next_arg(T_INT);
     // Copy the java argument value to kernelArgBuffer
@@ -67,7 +72,10 @@
   return;
 }
 
-void PTXKernelArguments::do_long()    {
+void PTXKernelArguments::do_long() {
+  if (is_after_invocation()) {
+    return;
+  }
   // If the parameter is a return value,
   if (is_return_type()) {
     // Allocate device memory for T_LONG return value pointer on device. Size in bytes
@@ -80,8 +88,7 @@
     // Push _return_value_ptr to _kernelBuffer
     *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
     _bufferOffset += sizeof(_return_value_ptr);
-  }
-  else {
+  } else {
     // Get the next java argument and its value which should be a T_LONG
     oop arg = next_arg(T_LONG);
     // Copy the java argument value to kernelArgBuffer
@@ -97,34 +104,81 @@
   return;
 }
 
-void PTXKernelArguments::do_byte()    {
-  // If the parameter is a return value,
-  if (is_return_type()) {
-    // Allocate device memory for T_BYTE return value pointer on device. Size in bytes
-    int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_BYTE_SIZE);
+void PTXKernelArguments::do_byte() {
+    if (is_after_invocation()) {
+        return;
+    }
+    // If the parameter is a return value,
+    if (is_return_type()) {
+        // Allocate device memory for T_BYTE return value pointer on device. Size in bytes
+        int status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, T_BYTE_SIZE);
+        if (status != GRAAL_CUDA_SUCCESS) {
+            tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
+            _success = false;
+            return;
+        }
+        // Push _return_value_ptr to _kernelBuffer
+        *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
+        _bufferOffset += sizeof(_return_value_ptr);
+    } else {
+        // Get the next java argument and its value which should be a T_BYTE
+        oop arg = next_arg(T_BYTE);
+        // Copy the java argument value to kernelArgBuffer
+        jvalue val;
+        if (java_lang_boxing_object::get_value(arg, &val) != T_BYTE) {
+            tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_BYTE");
+            _success = false;
+            return;
+        }
+        *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.b;
+        _bufferOffset += sizeof(val.b);
+    }
+    return;
+}
+
+void PTXKernelArguments::do_array(int begin, int end) {
+    gpu::Ptx::CUdeviceptr _array_ptr;
+    int status;
+
+    // Get the next java argument and its value which should be a T_ARRAY
+    oop arg = next_arg(T_OBJECT);
+    int array_size = arg->size() * HeapWordSize;
+
+    if (is_after_invocation()) {
+        _array_ptr = *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]);
+        status = gpu::Ptx::_cuda_cu_memcpy_dtoh(arg, _array_ptr, array_size);
+        if (status != GRAAL_CUDA_SUCCESS) {
+            tty->print_cr("[CUDA] *** Error (%d) Failed to copy array argument to host", status);
+            _success = false;
+            return;
+        } else {
+            // tty->print_cr("device: %x host: %x size: %d", _array_ptr, arg, array_size);
+        }
+        return;
+    }
+    // Allocate device memory for T_ARRAY return value pointer on device. Size in bytes
+    status = gpu::Ptx::_cuda_cu_memalloc(&_return_value_ptr, array_size);
     if (status != GRAAL_CUDA_SUCCESS) {
-      tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
-      _success = false;
-      return;
+        tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status);
+        _success = false;
+        return;
+    }
+    status = gpu::Ptx::_cuda_cu_memcpy_htod(_return_value_ptr, arg, array_size);
+    if (status != GRAAL_CUDA_SUCCESS) {
+        tty->print_cr("[CUDA] *** Error (%d) Failed to copy array to device argument", status);
+        _success = false;
+        return;
+    } else {
+        // tty->print_cr("host: %x device: %x size: %d", arg, _return_value_ptr, array_size);
     }
     // Push _return_value_ptr to _kernelBuffer
     *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _return_value_ptr;
     _bufferOffset += sizeof(_return_value_ptr);
-  }
-  else {
-    // Get the next java argument and its value which should be a T_BYTE
-    oop arg = next_arg(T_BYTE);
-    // Copy the java argument value to kernelArgBuffer
-    jvalue val;
-    if (java_lang_boxing_object::get_value(arg, &val) != T_BYTE) {
-      tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_BYTE");
-      _success = false;
-      return;
-    }
-    *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.b;
-    _bufferOffset += sizeof(val.b);
-  }
-  return;
+    return;
+}
+
+void PTXKernelArguments::do_void() {
+    return;
 }
 
 // TODO implement other do_*
--- a/src/gpu/ptx/vm/ptxKernelArguments.hpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/gpu/ptx/vm/ptxKernelArguments.hpp	Mon Sep 30 18:05:25 2013 +0200
@@ -31,6 +31,7 @@
 #define T_BYTE_SIZE       1
 #define T_INT_BYTE_SIZE   4
 #define T_LONG_BYTE_SIZE  8
+#define T_ARRAY_BYTE_SIZE 8
 
 class PTXKernelArguments : public SignatureIterator {
 public:
@@ -46,6 +47,8 @@
   int _index;
   // Flag to indicate successful creation of kernel argument buffer
   bool _success;
+
+    bool _afterInvoocation;
   // Get next java argument
   oop next_arg(BasicType expectedType);
 
@@ -74,6 +77,17 @@
     return _bufferOffset;
   }
 
+    void reiterate() {
+        _afterInvoocation = true;
+        _bufferOffset = 0;
+        _index = 0;
+        iterate();
+    }
+
+    inline bool is_after_invocation() {
+        return _afterInvoocation;
+    }
+
   // Get the return oop value
   oop get_return_oop();
 
@@ -86,44 +100,40 @@
   void do_byte();
   void do_int();
   void do_long();
+  void do_array(int begin, int end);
+  void do_void();
 
   inline void do_bool()   {
     /* TODO : To be implemented */
-    guarantee(false, "NYI");
+    guarantee(false, "do_bool:NYI");
   }
   inline void do_char()   {
     /* TODO : To be implemented */
-    guarantee(false, "NYI");
+    guarantee(false, "do_char:NYI");
   }
   inline void do_short()  {
     /* TODO : To be implemented */
-    guarantee(false, "NYI");
+    guarantee(false, "do_short:NYI");
   }
   inline void do_float()  {
     /* TODO : To be implemented */
-    guarantee(false, "NYI");
+    guarantee(false, "do_float:NYI");
   }
   inline void do_double() {
     /* TODO : To be implemented */
-    guarantee(false, "NYI");
+    guarantee(false, "do_double:NYI");
   }
 
   inline void do_object() {
     /* TODO : To be implemented */
-    guarantee(false, "NYI");
+    guarantee(false, "do_object:NYI");
   }
+    
   inline void do_object(int begin, int end) {
     /* TODO : To be implemented */
-    guarantee(false, "NYI");
+    guarantee(false, "do_object(II):NYI");
   }
-  inline void do_array(int begin, int end)  {
-    /* TODO : To be implemented */
-    guarantee(false, "NYI");
-  }
-  inline void do_void() {
-    /* TODO : To be implemented */
-    guarantee(false, "NYI");
-  }
+
 };
 
 #endif  // KERNEL_ARGUMENTS_HPP
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Mon Sep 30 18:05:25 2013 +0200
@@ -727,7 +727,7 @@
 
   oop debug_info = CompilationResult_Call::debugInfo(site);
 
-  assert((hotspot_method ? 1 : 0) + (foreign_call ? 1 : 0) == 1, "Call site needs exactly one type");
+  assert(!!hotspot_method ^ !!foreign_call, "Call site needs exactly one type");
 
   NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset);
   jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method);
--- a/src/share/vm/graal/graalCompilerToGPU.cpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToGPU.cpp	Mon Sep 30 18:05:25 2013 +0200
@@ -103,6 +103,45 @@
 
 C2V_END
 
+C2V_VMENTRY(jobject, executeParallelMethodVarargs, (JNIEnv *env,
+                                                          jobject,
+                                                          jint dimX, jint dimY, jint dimZ,
+                                                          jobject args, jobject hotspotInstalledCode))
+  ResourceMark rm;
+  HandleMark hm;
+
+  if (gpu::is_available() == false || gpu::has_gpu_linkage() == false && gpu::is_initialized()) {
+    tty->print_cr("executeExternalMethodVarargs - not available / no linkage / not initialized");
+    return NULL;
+  }
+  jlong nmethodValue = HotSpotInstalledCode::codeBlob(hotspotInstalledCode);
+  nmethod* nm = (nmethod*) (address) nmethodValue;
+  methodHandle mh = nm->method();
+  Symbol* signature = mh->signature();
+
+  // start value is the kernel
+  jlong startValue = HotSpotInstalledCode::codeStart(hotspotInstalledCode);
+
+  PTXKernelArguments ptxka(signature, (arrayOop) JNIHandles::resolve(args), mh->is_static());
+  JavaValue result(ptxka.get_ret_type());
+if (!gpu::execute_warp(dimX, dimY, dimZ, (address)startValue, ptxka, result)) {
+    return NULL;
+  }
+
+  if (ptxka.get_ret_type() == T_VOID) {
+    return NULL;
+  } else if (ptxka.get_ret_type() == T_OBJECT || ptxka.get_ret_type() == T_ARRAY) {
+    return JNIHandles::make_local((oop) result.get_jobject());
+  } else {
+    oop o = java_lang_boxing_object::create(ptxka.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL);
+    if (TraceGPUInteraction) {
+      tty->print_cr("GPU execution returned %d", result.get_jint());
+    }
+    return JNIHandles::make_local(o);
+  }
+
+C2V_END
+
 C2V_VMENTRY(jboolean, deviceInit, (JNIEnv *env, jobject))
   if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) {
     tty->print_cr("deviceInit - not available / no linkage");
@@ -157,10 +196,11 @@
 #define GPUSPACE_METHOD       "J"
 
 JNINativeMethod CompilerToGPU_methods[] = {
-  {CC"generateKernel",                CC"([B" STRING ")"GPUSPACE_METHOD,        FN_PTR(generateKernel)},
-  {CC"deviceInit",                    CC"()Z",                                  FN_PTR(deviceInit)},
-  {CC"deviceDetach",                  CC"()Z",                                  FN_PTR(deviceDetach)},
-  {CC"executeExternalMethodVarargs",  CC"(["OBJECT HS_INSTALLED_CODE")"OBJECT,  FN_PTR(executeExternalMethodVarargs)},
+  {CC"generateKernel",                CC"([B" STRING ")"GPUSPACE_METHOD,          FN_PTR(generateKernel)},
+  {CC"deviceInit",                    CC"()Z",                                    FN_PTR(deviceInit)},
+  {CC"deviceDetach",                  CC"()Z",                                    FN_PTR(deviceDetach)},
+  {CC"executeExternalMethodVarargs",  CC"(["OBJECT HS_INSTALLED_CODE")"OBJECT,    FN_PTR(executeExternalMethodVarargs)},
+  {CC"executeParallelMethodVarargs",  CC"(III["OBJECT HS_INSTALLED_CODE")"OBJECT, FN_PTR(executeParallelMethodVarargs)},
 };
 
 int CompilerToGPU_methods_count() {
--- a/src/share/vm/runtime/gpu.cpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/share/vm/runtime/gpu.cpp	Mon Sep 30 18:05:25 2013 +0200
@@ -61,12 +61,23 @@
 }
 
 bool gpu::execute_kernel(address kernel, PTXKernelArguments & ptxka, JavaValue& ret) {
-  if (gpu::has_gpu_linkage()) {
-    if (gpu::get_target_il_type() == gpu::PTX) {
-      return (gpu::Ptx::execute_kernel(kernel, ptxka, ret));
+    if (gpu::has_gpu_linkage()) {
+        if (gpu::get_target_il_type() == gpu::PTX) {
+            return (gpu::Ptx::execute_kernel(kernel, ptxka, ret));
+        }
+        // Add kernel execution functionality of other GPUs here
     }
-    // Add kernel execution functionality of other GPUs here
-  }
-  return false;
+    return false;
 }
 
+bool gpu::execute_warp(int dimX, int dimY, int dimZ,
+                       address kernel, PTXKernelArguments & ptxka, JavaValue& ret) {
+    if (gpu::has_gpu_linkage()) {
+        if (gpu::get_target_il_type() == gpu::PTX) {
+            return (gpu::Ptx::execute_warp(dimX, dimY, dimZ, kernel, ptxka, ret));
+        }
+        // Add kernel execution functionality of other GPUs here
+    }
+    return false;
+}
+
--- a/src/share/vm/runtime/gpu.hpp	Thu Sep 26 17:33:04 2013 +0200
+++ b/src/share/vm/runtime/gpu.hpp	Mon Sep 30 18:05:25 2013 +0200
@@ -46,6 +46,9 @@
   
   static void * generate_kernel(unsigned char *code, int code_len, const char *name);
 
+  static bool execute_warp(int dimX, int dimY, int dimZ,
+                           address kernel, PTXKernelArguments & ptxka, JavaValue & ret);
+
   static bool execute_kernel(address kernel, PTXKernelArguments & ptxka, JavaValue & ret);
 
   static void set_available(bool value) {