8144704: [JVMCI] add tests for simple code installation
authorrschatz
Tue, 15 Dec 2015 16:55:24 +0100
changeset 35137 c8f8f6de68a7
parent 35136 f3788128ff3f
child 35138 de9e69473956
8144704: [JVMCI] add tests for simple code installation Reviewed-by: twisti
hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp
hotspot/test/compiler/jvmci/code/CodeInstallationTest.java
hotspot/test/compiler/jvmci/code/DataPatchTest.java
hotspot/test/compiler/jvmci/code/DebugInfoTest.java
hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java
hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java
hotspot/test/compiler/jvmci/code/TestAssembler.java
hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java
hotspot/test/compiler/jvmci/code/amd64/AMD64TestAssembler.java
hotspot/test/compiler/jvmci/code/sparc/SPARCTestAssembler.java
--- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp	Fri Dec 18 15:29:43 2015 -0800
+++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp	Tue Dec 15 16:55:24 2015 +0100
@@ -179,7 +179,7 @@
   nonstatic_field(Method,                      _access_flags,                                 AccessFlags)                           \
   nonstatic_field(Method,                      _vtable_index,                                 int)                                   \
   nonstatic_field(Method,                      _intrinsic_id,                                 u2)                                    \
-  nonstatic_field(Method,                      _flags,                                        u1)                                    \
+  nonstatic_field(Method,                      _flags,                                        u2)                                    \
   volatile_nonstatic_field(Method,             _code,                                         nmethod*)                              \
   volatile_nonstatic_field(Method,             _from_compiled_entry,                          address)                               \
                                                                                                                                      \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/CodeInstallationTest.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 compiler.jvmci.code;
+
+import java.lang.reflect.Method;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CompilationResult;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.runtime.JVMCI;
+import jdk.vm.ci.runtime.JVMCIBackend;
+import jdk.vm.ci.sparc.SPARC;
+
+import org.junit.Assert;
+
+import compiler.jvmci.code.amd64.AMD64TestAssembler;
+import compiler.jvmci.code.sparc.SPARCTestAssembler;
+
+/**
+ * Base class for code installation tests.
+ */
+public class CodeInstallationTest {
+
+    protected final MetaAccessProvider metaAccess;
+    protected final CodeCacheProvider codeCache;
+    protected final TargetDescription target;
+    protected final ConstantReflectionProvider constantReflection;
+
+    public CodeInstallationTest() {
+        JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend();
+        metaAccess = backend.getMetaAccess();
+        codeCache = backend.getCodeCache();
+        target = backend.getTarget();
+        constantReflection = backend.getConstantReflection();
+    }
+
+    protected interface TestCompiler {
+
+        void compile(TestAssembler asm);
+    }
+
+    private TestAssembler createAssembler(CompilationResult result) {
+        Architecture arch = codeCache.getTarget().arch;
+        if (arch instanceof AMD64) {
+            return new AMD64TestAssembler(result, codeCache);
+        } else if (arch instanceof SPARC) {
+            return new SPARCTestAssembler(result, codeCache);
+        } else {
+            Assert.fail("unsupported architecture");
+            return null;
+        }
+    }
+
+    protected Method getMethod(String name, Class<?>... args) {
+        try {
+            return getClass().getMethod(name, args);
+        } catch (NoSuchMethodException e) {
+            Assert.fail("method not found");
+            return null;
+        }
+    }
+
+    protected void test(TestCompiler compiler, Method method, Object... args) {
+        CompilationResult result = new CompilationResult(method.getName());
+        TestAssembler asm = createAssembler(result);
+
+        asm.emitPrologue();
+        compiler.compile(asm);
+        asm.finish();
+
+        result.close();
+
+        ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(method);
+        InstalledCode installed = codeCache.addCode(resolvedMethod, result, null, null);
+
+        try {
+            Object expected = method.invoke(null, args);
+            Object actual = installed.executeVarargs(args);
+            Assert.assertEquals(expected, actual);
+        } catch (Exception e) {
+            e.printStackTrace();
+            Assert.fail(e.toString());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/DataPatchTest.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @compile CodeInstallationTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.DataPatchTest
+ */
+
+package compiler.jvmci.code;
+
+import jdk.vm.ci.code.CompilationResult.DataSectionReference;
+import jdk.vm.ci.code.DataSection.Data;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.junit.Assume;
+import org.junit.Test;
+
+/**
+ * Test code installation with data patches.
+ */
+public class DataPatchTest extends CodeInstallationTest {
+
+    public static Class<?> getConstClass() {
+        return DataPatchTest.class;
+    }
+
+    private void test(TestCompiler compiler) {
+        test(compiler, getMethod("getConstClass"));
+    }
+
+
+    @Test
+    public void testInlineObject() {
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            HotSpotConstant c = (HotSpotConstant) type.getJavaClass();
+            Register ret = asm.emitLoadPointer(c);
+            asm.emitPointerRet(ret);
+        });
+    }
+
+    @Test
+    public void testInlineNarrowObject() {
+        Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops);
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            HotSpotConstant c = (HotSpotConstant) type.getJavaClass();
+            Register compressed = asm.emitLoadPointer((HotSpotConstant) c.compress());
+            Register ret = asm.emitUncompressPointer(compressed, HotSpotVMConfig.config().narrowOopBase, HotSpotVMConfig.config().narrowOopShift);
+            asm.emitPointerRet(ret);
+        });
+    }
+
+    @Test
+    public void testDataSectionReference() {
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            HotSpotConstant c = (HotSpotConstant) type.getJavaClass();
+            Data data = codeCache.createDataItem(c);
+            DataSectionReference ref = asm.result.getDataSection().insertData(data);
+            Register ret = asm.emitLoadPointer(ref);
+            asm.emitPointerRet(ret);
+        });
+    }
+
+    @Test
+    public void testNarrowDataSectionReference() {
+        Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops);
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            HotSpotConstant c = (HotSpotConstant) type.getJavaClass();
+            HotSpotConstant cCompressed = (HotSpotConstant) c.compress();
+            Data data = codeCache.createDataItem(cCompressed);
+            DataSectionReference ref = asm.result.getDataSection().insertData(data);
+            Register compressed = asm.emitLoadNarrowPointer(ref);
+            Register ret = asm.emitUncompressPointer(compressed, HotSpotVMConfig.config().narrowOopBase, HotSpotVMConfig.config().narrowOopShift);
+            asm.emitPointerRet(ret);
+        });
+    }
+
+    @Test
+    public void testInlineMetadata() {
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            Register klass = asm.emitLoadPointer((HotSpotConstant) type.getObjectHub());
+            Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset);
+            asm.emitPointerRet(ret);
+        });
+    }
+
+    @Test
+    public void testInlineNarrowMetadata() {
+        Assume.assumeTrue(HotSpotVMConfig.config().useCompressedClassPointers);
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            HotSpotConstant hub = (HotSpotConstant) type.getObjectHub();
+            Register narrowKlass = asm.emitLoadPointer((HotSpotConstant) hub.compress());
+            Register klass = asm.emitUncompressPointer(narrowKlass, HotSpotVMConfig.config().narrowKlassBase, HotSpotVMConfig.config().narrowKlassShift);
+            Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset);
+            asm.emitPointerRet(ret);
+        });
+    }
+
+    @Test
+    public void testMetadataInDataSection() {
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            HotSpotConstant hub = (HotSpotConstant) type.getObjectHub();
+            Data data = codeCache.createDataItem(hub);
+            DataSectionReference ref = asm.result.getDataSection().insertData(data);
+            Register klass = asm.emitLoadPointer(ref);
+            Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset);
+            asm.emitPointerRet(ret);
+        });
+    }
+
+    @Test
+    public void testNarrowMetadataInDataSection() {
+        Assume.assumeTrue(HotSpotVMConfig.config().useCompressedClassPointers);
+        test(asm -> {
+            ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
+            HotSpotConstant hub = (HotSpotConstant) type.getObjectHub();
+            HotSpotConstant narrowHub = (HotSpotConstant) hub.compress();
+            Data data = codeCache.createDataItem(narrowHub);
+            DataSectionReference ref = asm.result.getDataSection().insertData(data);
+            Register narrowKlass = asm.emitLoadNarrowPointer(ref);
+            Register klass = asm.emitUncompressPointer(narrowKlass, HotSpotVMConfig.config().narrowKlassBase, HotSpotVMConfig.config().narrowKlassShift);
+            Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset);
+            asm.emitPointerRet(ret);
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/DebugInfoTest.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 compiler.jvmci.code;
+
+import java.lang.reflect.Method;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.Location;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.hotspot.HotSpotReferenceMap;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Test code installation with debug information.
+ */
+public class DebugInfoTest extends CodeInstallationTest {
+
+    protected interface DebugInfoCompiler {
+
+        VirtualObject[] compile(TestAssembler asm, JavaValue[] frameValues);
+    }
+
+    protected void test(DebugInfoCompiler compiler, Method method, int bci, JavaKind... slotKinds) {
+        ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(method);
+
+        int numLocals = resolvedMethod.getMaxLocals();
+        int numStack = slotKinds.length - numLocals;
+        JavaValue[] values = new JavaValue[slotKinds.length];
+        test(asm -> {
+            VirtualObject[] vobjs = compiler.compile(asm, values);
+
+            BytecodeFrame frame = new BytecodeFrame(null, resolvedMethod, bci, false, false, values, slotKinds, numLocals, numStack, 0);
+            DebugInfo info = new DebugInfo(frame, vobjs);
+            info.setReferenceMap(new HotSpotReferenceMap(new Location[0], new Location[0], new int[0], 8));
+
+            asm.emitTrap(info);
+        }, method);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @compile CodeInstallationTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.SimpleCodeInstallationTest
+ */
+
+package compiler.jvmci.code;
+
+import jdk.vm.ci.code.Register;
+
+import org.junit.Test;
+
+/**
+ * Test simple code installation.
+ */
+public class SimpleCodeInstallationTest extends CodeInstallationTest {
+
+    public static int add(int a, int b) {
+        return a + b;
+    }
+
+    private static void compileAdd(TestAssembler asm) {
+        Register arg0 = asm.emitIntArg0();
+        Register arg1 = asm.emitIntArg1();
+        Register ret = asm.emitIntAdd(arg0, arg1);
+        asm.emitIntRet(ret);
+    }
+
+    @Test
+    public void test() {
+        test(SimpleCodeInstallationTest::compileAdd, getMethod("add", int.class, int.class), 5, 7);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @compile CodeInstallationTest.java DebugInfoTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.SimpleDebugInfoTest
+ */
+
+package compiler.jvmci.code;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Value;
+
+import org.junit.Assume;
+import org.junit.Test;
+
+public class SimpleDebugInfoTest extends DebugInfoTest {
+
+    public static int intOnStack() {
+        return 42;
+    }
+
+    private void testIntOnStack(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("intOnStack"), 2, JavaKind.Int);
+    }
+
+    public static int intInLocal() {
+        int local = 42;
+        return local;
+    }
+
+    public void testIntInLocal(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("intInLocal"), 3, JavaKind.Int);
+    }
+
+    @Test
+    public void testConstInt() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            values[0] = JavaConstant.forInt(42);
+            return null;
+        };
+        testIntOnStack(compiler);
+        testIntInLocal(compiler);
+    }
+
+    @Test
+    public void testRegInt() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadInt(42);
+            values[0] = reg.asValue(target.getLIRKind(JavaKind.Int));
+            return null;
+        };
+        testIntOnStack(compiler);
+        testIntInLocal(compiler);
+    }
+
+    @Test
+    public void testStackInt() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadInt(42);
+            values[0] = asm.emitIntToStack(reg);
+            return null;
+        };
+        testIntOnStack(compiler);
+        testIntInLocal(compiler);
+    }
+
+
+    public static float floatOnStack() {
+        return 42.0f;
+    }
+
+    private void testFloatOnStack(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("floatOnStack"), 2, JavaKind.Float);
+    }
+
+    public static float floatInLocal() {
+        float local = 42.0f;
+        return local;
+    }
+
+    private void testFloatInLocal(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("floatInLocal"), 3, JavaKind.Float);
+    }
+
+    @Test
+    public void testConstFloat() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            values[0] = JavaConstant.forFloat(42.0f);
+            return null;
+        };
+        testFloatOnStack(compiler);
+        testFloatInLocal(compiler);
+    }
+
+    @Test
+    public void testRegFloat() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadFloat(42.0f);
+            values[0] = reg.asValue(target.getLIRKind(JavaKind.Float));
+            return null;
+        };
+        testFloatOnStack(compiler);
+        testFloatInLocal(compiler);
+    }
+
+    @Test
+    public void testStackFloat() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadFloat(42.0f);
+            values[0] = asm.emitFloatToStack(reg);
+            return null;
+        };
+        testFloatOnStack(compiler);
+        testFloatInLocal(compiler);
+    }
+
+
+    public static long longOnStack() {
+        return 42;
+    }
+
+    private void testLongOnStack(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("longOnStack"), 3, JavaKind.Long, JavaKind.Illegal);
+    }
+
+    public static long longInLocal() {
+        long local = 42;
+        return local;
+    }
+
+    private void testLongInLocal(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("longInLocal"), 4, JavaKind.Long, JavaKind.Illegal);
+    }
+
+    @Test
+    public void testConstLong() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            values[0] = JavaConstant.forLong(42);
+            values[1] = Value.ILLEGAL;
+            return null;
+        };
+        testLongOnStack(compiler);
+        testLongInLocal(compiler);
+    }
+
+    @Test
+    public void testRegLong() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadLong(42);
+            values[0] = reg.asValue(target.getLIRKind(JavaKind.Long));
+            values[1] = Value.ILLEGAL;
+            return null;
+        };
+        testLongOnStack(compiler);
+        testLongInLocal(compiler);
+    }
+
+    @Test
+    public void testStackLong() {
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadLong(42);
+            values[0] = asm.emitLongToStack(reg);
+            values[1] = Value.ILLEGAL;
+            return null;
+        };
+        testLongOnStack(compiler);
+        testLongInLocal(compiler);
+    }
+
+
+    public static Class<?> objectOnStack() {
+        return SimpleDebugInfoTest.class;
+    }
+
+    private void testObjectOnStack(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("objectOnStack"), 2, JavaKind.Object);
+    }
+
+    public static Class<?> objectInLocal() {
+        Class<?> local = SimpleDebugInfoTest.class;
+        return local;
+    }
+
+    private void testObjectInLocal(DebugInfoCompiler compiler) {
+        test(compiler, getMethod("objectInLocal"), 3, JavaKind.Object);
+    }
+
+    @Test
+    public void testConstObject() {
+        ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack());
+        DebugInfoCompiler compiler = (asm, values) -> {
+            values[0] = type.getJavaClass();
+            return null;
+        };
+        testObjectOnStack(compiler);
+        testObjectInLocal(compiler);
+    }
+
+    @Test
+    public void testRegObject() {
+        ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack());
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadPointer((HotSpotConstant) type.getJavaClass());
+            values[0] = reg.asValue(target.getLIRKind(JavaKind.Object));
+            return null;
+        };
+        testObjectOnStack(compiler);
+        testObjectInLocal(compiler);
+    }
+
+    @Test
+    public void testStackObject() {
+        ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack());
+        DebugInfoCompiler compiler = (asm, values) -> {
+            Register reg = asm.emitLoadPointer((HotSpotConstant) type.getJavaClass());
+            values[0] = asm.emitPointerToStack(reg);
+            return null;
+        };
+        testObjectOnStack(compiler);
+        testObjectInLocal(compiler);
+    }
+
+    @Test
+    public void testRegNarrowObject() {
+        Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops);
+        ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack());
+        DebugInfoCompiler compiler = (asm, values) -> {
+            HotSpotConstant wide = (HotSpotConstant) type.getJavaClass();
+            Register reg = asm.emitLoadPointer((HotSpotConstant) wide.compress());
+            values[0] = reg.asValue(asm.narrowOopKind);
+            return null;
+        };
+        testObjectOnStack(compiler);
+        testObjectInLocal(compiler);
+    }
+
+    @Test
+    public void testStackNarrowObject() {
+        Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops);
+        ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack());
+        DebugInfoCompiler compiler = (asm, values) -> {
+            HotSpotConstant wide = (HotSpotConstant) type.getJavaClass();
+            Register reg = asm.emitLoadPointer((HotSpotConstant) wide.compress());
+            values[0] = asm.emitNarrowPointerToStack(reg);
+            return null;
+        };
+        testObjectOnStack(compiler);
+        testObjectInLocal(compiler);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/TestAssembler.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 compiler.jvmci.code;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CompilationResult;
+import jdk.vm.ci.code.CompilationResult.DataSectionReference;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.PlatformKind;
+
+/**
+ * Simple assembler used by the code installation tests.
+ */
+public abstract class TestAssembler {
+
+    /**
+     * Emit the method prologue code (e.g. building the new stack frame).
+     */
+    public abstract void emitPrologue();
+
+    /**
+     * Emit code to grow the stack frame.
+     * @param size the size in bytes that the stack should grow
+     */
+    public abstract void emitGrowStack(int size);
+
+    /**
+     * Get the register containing the first 32-bit integer argument.
+     */
+    public abstract Register emitIntArg0();
+
+    /**
+     * Get the register containing the second 32-bit integer argument.
+     */
+    public abstract Register emitIntArg1();
+
+    /**
+     * Emit code to add two 32-bit integer registers. May reuse one of the argument registers.
+     */
+    public abstract Register emitIntAdd(Register a, Register b);
+
+    /**
+     * Emit code to load a constant 32-bit integer to a register.
+     */
+    public abstract Register emitLoadInt(int value);
+
+    /**
+     * Emit code to load a constant 64-bit integer to a register.
+     */
+    public abstract Register emitLoadLong(long value);
+
+    /**
+     * Emit code to load a constant single-precision float to a register.
+     */
+    public abstract Register emitLoadFloat(float value);
+
+    /**
+     * Emit code to load a constant oop or metaspace pointer to a register.
+     * The pointer may be wide or narrow, depending on {@link HotSpotConstant#isCompressed() c.isCompressed()}.
+     */
+    public abstract Register emitLoadPointer(HotSpotConstant c);
+
+    /**
+     * Emit code to load a wide pointer from the {@link DataSection} to a register.
+     */
+    public abstract Register emitLoadPointer(DataSectionReference ref);
+
+    /**
+     * Emit code to load a narrow pointer from the {@link DataSection} to a register.
+     */
+    public abstract Register emitLoadNarrowPointer(DataSectionReference ref);
+
+    /**
+     * Emit code to load a (wide) pointer from a memory location to a register.
+     */
+    public abstract Register emitLoadPointer(Register base, int offset);
+
+    /**
+     * Emit code to store a 32-bit integer from a register to a new stack slot.
+     */
+    public abstract StackSlot emitIntToStack(Register a);
+
+    /**
+     * Emit code to store a 64-bit integer from a register to a new stack slot.
+     */
+    public abstract StackSlot emitLongToStack(Register a);
+
+    /**
+     * Emit code to store a single-precision float from a register to a new stack slot.
+     */
+    public abstract StackSlot emitFloatToStack(Register a);
+
+    /**
+     * Emit code to store a wide pointer from a register to a new stack slot.
+     */
+    public abstract StackSlot emitPointerToStack(Register a);
+
+    /**
+     * Emit code to store a narrow pointer from a register to a new stack slot.
+     */
+    public abstract StackSlot emitNarrowPointerToStack(Register a);
+
+    /**
+     * Emit code to uncompress a narrow pointer. The input pointer is guaranteed to be non-null.
+     */
+    public abstract Register emitUncompressPointer(Register compressed, long base, int shift);
+
+    /**
+     * Emit code to return from a function, returning a 32-bit integer.
+     */
+    public abstract void emitIntRet(Register a);
+
+    /**
+     * Emit code to return from a function, returning a wide oop pointer.
+     */
+    public abstract void emitPointerRet(Register a);
+
+    /**
+     * Emit code that traps, forcing a deoptimization.
+     */
+    public abstract void emitTrap(DebugInfo info);
+
+    protected int position() {
+        return data.position();
+    }
+
+    public final CompilationResult result;
+    public final LIRKind narrowOopKind;
+
+    private ByteBuffer data;
+    protected final CodeCacheProvider codeCache;
+
+    private final Register[] registers;
+    private int nextRegister;
+
+    protected int frameSize;
+    private int stackAlignment;
+    private int curStackSlot;
+
+    protected TestAssembler(CompilationResult result, CodeCacheProvider codeCache, int initialFrameSize, int stackAlignment, PlatformKind narrowOopKind, Register... registers) {
+        this.result = result;
+        this.narrowOopKind = LIRKind.reference(narrowOopKind);
+
+        this.data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder());
+        this.codeCache = codeCache;
+
+        this.registers = registers;
+        this.nextRegister = 0;
+
+        this.frameSize = initialFrameSize;
+        this.stackAlignment = stackAlignment;
+        this.curStackSlot = initialFrameSize;
+    }
+
+    protected Register newRegister() {
+        return registers[nextRegister++];
+    }
+
+    protected StackSlot newStackSlot(LIRKind kind) {
+        curStackSlot += kind.getPlatformKind().getSizeInBytes();
+        if (curStackSlot > frameSize) {
+            int newFrameSize = curStackSlot;
+            if (newFrameSize % stackAlignment != 0) {
+                newFrameSize += stackAlignment - (newFrameSize % stackAlignment);
+            }
+            emitGrowStack(newFrameSize - frameSize);
+            frameSize = newFrameSize;
+        }
+        return StackSlot.get(kind, -curStackSlot, true);
+    }
+
+    public void finish() {
+        result.setTotalFrameSize(frameSize);
+        result.setTargetCode(data.array(), data.position());
+    }
+
+    private void ensureSize(int length) {
+        if (length >= data.limit()) {
+            byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
+            ByteBuffer newData = ByteBuffer.wrap(newBuf);
+            newData.order(data.order());
+            newData.position(data.position());
+            data = newData;
+        }
+    }
+
+    protected void emitByte(int b) {
+        ensureSize(data.position() + 1);
+        data.put((byte) (b & 0xFF));
+    }
+
+    protected void emitShort(int b) {
+        ensureSize(data.position() + 2);
+        data.putShort((short) b);
+    }
+
+    protected void emitInt(int b) {
+        ensureSize(data.position() + 4);
+        data.putInt(b);
+    }
+
+    protected void emitLong(long b) {
+        ensureSize(data.position() + 8);
+        data.putLong(b);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
+ * @compile CodeInstallationTest.java DebugInfoTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.VirtualObjectDebugInfoTest
+ */
+
+package compiler.jvmci.code;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class VirtualObjectDebugInfoTest extends DebugInfoTest {
+
+    private static class TestClass {
+
+        private long longField;
+        private int intField;
+        private float floatField;
+        private Object[] arrayField;
+
+        public TestClass() {
+            this.longField = 8472;
+            this.intField = 42;
+            this.floatField = 3.14f;
+            this.arrayField = new Object[] { Integer.valueOf(58), this, null, Integer.valueOf(17), "Hello, World!" };
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof TestClass)) {
+                return false;
+            }
+
+            TestClass other = (TestClass) o;
+            if (this.longField != other.longField
+                || this.intField != other.intField
+                || this.floatField != other.floatField
+                || this.arrayField.length != other.arrayField.length) {
+                return false;
+            }
+
+            for (int i = 0; i < this.arrayField.length; i++) {
+                // break cycle
+                if (this.arrayField[i] == this && other.arrayField[i] == other) {
+                    continue;
+                }
+
+                if (!Objects.equals(this.arrayField[i], other.arrayField[i])) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    public static TestClass buildObject() {
+        return new TestClass();
+    }
+
+    private VirtualObject[] compileBuildObject(TestAssembler asm, JavaValue[] values) {
+        TestClass template = new TestClass();
+        ArrayList<VirtualObject> vobjs = new ArrayList<>();
+
+        ResolvedJavaType retType = metaAccess.lookupJavaType(TestClass.class);
+        VirtualObject ret = VirtualObject.get(retType, vobjs.size());
+        vobjs.add(ret);
+        values[0] = ret;
+
+        ResolvedJavaType arrayType = metaAccess.lookupJavaType(Object[].class);
+        VirtualObject array = VirtualObject.get(arrayType, vobjs.size());
+        vobjs.add(array);
+
+        // build array for ret.arrayField
+        ResolvedJavaType integerType = metaAccess.lookupJavaType(Integer.class);
+        JavaValue[] arrayContent = new JavaValue[template.arrayField.length];
+        JavaKind[] arrayKind = new JavaKind[template.arrayField.length];
+        for (int i = 0; i < arrayContent.length; i++) {
+            arrayKind[i] = JavaKind.Object;
+            if (template.arrayField[i] == null) {
+                arrayContent[i] = JavaConstant.NULL_POINTER;
+            } else if (template.arrayField[i] == template) {
+                arrayContent[i] = ret;
+            } else if (template.arrayField[i] instanceof Integer) {
+                int value = (Integer) template.arrayField[i];
+                VirtualObject boxed = VirtualObject.get(integerType, vobjs.size());
+                vobjs.add(boxed);
+                arrayContent[i] = boxed;
+                boxed.setValues(new JavaValue[]{JavaConstant.forInt(value)}, new JavaKind[]{JavaKind.Int});
+            } else if (template.arrayField[i] instanceof String) {
+                String value = (String) template.arrayField[i];
+                Register reg = asm.emitLoadPointer((HotSpotConstant) constantReflection.forString(value));
+                arrayContent[i] = reg.asValue(target.getLIRKind(JavaKind.Object));
+            } else {
+                Assert.fail("unexpected value");
+            }
+        }
+        array.setValues(arrayContent, arrayKind);
+
+        // build return object
+        ResolvedJavaField[] fields = retType.getInstanceFields(true);
+        JavaValue[] retContent = new JavaValue[fields.length];
+        JavaKind[] retKind = new JavaKind[fields.length];
+        for (int i = 0; i < fields.length; i++) {
+            retKind[i] = fields[i].getJavaKind();
+            switch (retKind[i]) {
+                case Long: // template.longField
+                    retContent[i] = JavaConstant.forLong(template.longField);
+                    break;
+                case Int: // template.intField
+                    Register intReg = asm.emitLoadInt(template.intField);
+                    retContent[i] = asm.emitIntToStack(intReg);
+                    break;
+                case Float: // template.floatField
+                    Register fReg = asm.emitLoadFloat(template.floatField);
+                    retContent[i] = fReg.asValue(target.getLIRKind(JavaKind.Float));
+                    break;
+                case Object: // template.arrayField
+                    retContent[i] = array;
+                    break;
+                default:
+                    Assert.fail("unexpected field");
+            }
+        }
+        ret.setValues(retContent, retKind);
+
+        return vobjs.toArray(new VirtualObject[0]);
+    }
+
+    @Test
+    public void testBuildObject() {
+        test(this::compileBuildObject, getMethod("buildObject"), 7, JavaKind.Object);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/amd64/AMD64TestAssembler.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 compiler.jvmci.code.amd64;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CompilationResult;
+import jdk.vm.ci.code.CompilationResult.ConstantReference;
+import jdk.vm.ci.code.CompilationResult.DataSectionReference;
+import jdk.vm.ci.code.DataSection.Data;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.InfopointReason;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.VMConstant;
+
+import compiler.jvmci.code.TestAssembler;
+
+public class AMD64TestAssembler extends TestAssembler {
+
+    public AMD64TestAssembler(CompilationResult result, CodeCacheProvider codeCache) {
+        super(result, codeCache, 16, 16, AMD64Kind.DWORD, AMD64.rax, AMD64.rcx, AMD64.rdi, AMD64.r8, AMD64.r9, AMD64.r10);
+    }
+
+    public void emitPrologue() {
+        emitByte(0x50 | AMD64.rbp.encoding);  // PUSH rbp
+        emitMove(true, AMD64.rbp, AMD64.rsp); // MOV rbp, rsp
+    }
+
+    public void emitGrowStack(int size) {
+        // SUB rsp, size
+        emitByte(0x48);
+        emitByte(0x81);
+        emitByte(0xEC);
+        emitInt(size);
+    }
+
+    public Register emitIntArg0() {
+        return AMD64.rsi;
+    }
+
+    public Register emitIntArg1() {
+        return AMD64.rdx;
+    }
+
+    private void emitREX(boolean w, int r, int x, int b) {
+        int wrxb = (w ? 0x08 : 0) | ((r >> 3) << 2) | ((x >> 3) << 1) | (b >> 3);
+        if (wrxb != 0) {
+            emitByte(0x40 | wrxb);
+        }
+    }
+
+    private void emitModRMReg(boolean w, int opcode, int r, int m) {
+        emitREX(w, r, 0, m);
+        emitByte((byte) opcode);
+        emitByte((byte) 0xC0 | ((r & 0x7) << 3) | (m & 0x7));
+    }
+
+    private void emitModRMMemory(boolean w, int opcode, int r, int b, int offset) {
+        emitREX(w, r, 0, b);
+        emitByte((byte) opcode);
+        emitByte((byte) 0x80 | ((r & 0x7) << 3) | (b & 0x7));
+        emitInt(offset);
+    }
+
+    public Register emitLoadInt(int c) {
+        Register ret = newRegister();
+        emitREX(false, 0, 0, ret.encoding);
+        emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32
+        emitInt(c);
+        return ret;
+    }
+
+    public Register emitLoadLong(long c) {
+        Register ret = newRegister();
+        emitREX(true, 0, 0, ret.encoding);
+        emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r64, imm64
+        emitLong(c);
+        return ret;
+    }
+
+    public Register emitLoadFloat(float c) {
+        Data data = codeCache.createDataItem(JavaConstant.forFloat(c));
+        DataSectionReference ref = result.getDataSection().insertData(data);
+        result.recordDataPatch(position(), ref);
+        Register ret = AMD64.xmm0;
+        emitREX(false, ret.encoding, 0, 0);
+        emitByte(0xF3);
+        emitByte(0x0F);
+        emitByte(0x10);                               // MOVSS xmm1, xmm2/m32
+        emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // xmm, [rip+offset]
+        emitInt(0xDEADDEAD);
+        return ret;
+    }
+
+    public Register emitLoadPointer(HotSpotConstant c) {
+        result.recordDataPatch(position(), new ConstantReference((VMConstant) c));
+        if (c.isCompressed()) {
+            Register ret = newRegister();
+            emitREX(false, 0, 0, ret.encoding);
+            emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32
+            emitInt(0xDEADDEAD);
+            return ret;
+        } else {
+            return emitLoadLong(0xDEADDEADDEADDEADl);
+        }
+    }
+
+    private Register emitLoadPointer(DataSectionReference ref, boolean narrow) {
+        result.recordDataPatch(position(), ref);
+        Register ret = newRegister();
+        emitREX(!narrow, ret.encoding, 0, 0);
+        emitByte(0x8B);                               // MOV r64,r/m64
+        emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // r64, [rip+offset]
+        emitInt(0xDEADDEAD);
+        return ret;
+    }
+
+    public Register emitLoadPointer(DataSectionReference ref) {
+        return emitLoadPointer(ref, false);
+    }
+
+    public Register emitLoadNarrowPointer(DataSectionReference ref) {
+        return emitLoadPointer(ref, true);
+    }
+
+    public Register emitLoadPointer(Register b, int offset) {
+        Register ret = newRegister();
+        emitModRMMemory(true, 0x8B, ret.encoding, b.encoding, offset); // MOV r64,r/m64
+        return ret;
+    }
+
+    public StackSlot emitIntToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.DWORD));
+        emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m32,r32
+        return ret;
+    }
+
+    public StackSlot emitLongToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.QWORD));
+        emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m64,r64
+        return ret;
+    }
+
+    public StackSlot emitFloatToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.SINGLE));
+        emitREX(false, a.encoding, 0, 0);
+        emitByte(0xF3);
+        emitByte(0x0F);
+        emitByte(0x11);                               // MOVSS xmm2/m32, xmm1
+        emitByte(0x85 | ((a.encoding & 0x7) << 3));   // [rbp+offset]
+        emitInt(ret.getRawOffset() + 16);
+        return ret;
+    }
+
+    public StackSlot emitPointerToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.reference(AMD64Kind.QWORD));
+        emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m64,r64
+        return ret;
+    }
+
+    public StackSlot emitNarrowPointerToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.reference(AMD64Kind.DWORD));
+        emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m32,r32
+        return ret;
+    }
+
+    public Register emitUncompressPointer(Register compressed, long base, int shift) {
+        if (shift > 0) {
+            emitModRMReg(true, 0xC1, 4, compressed.encoding);
+            emitByte(shift);
+        }
+        if (base == 0) {
+            return compressed;
+        } else {
+            Register tmp = emitLoadLong(base);
+            emitModRMReg(true, 0x03, tmp.encoding, compressed.encoding);
+            return tmp;
+        }
+    }
+
+    public Register emitIntAdd(Register a, Register b) {
+        emitModRMReg(false, 0x03, a.encoding, b.encoding);
+        return a;
+    }
+
+    private void emitMove(boolean w, Register to, Register from) {
+        if (to != from) {
+            emitModRMReg(w, 0x8B, to.encoding, from.encoding);
+        }
+    }
+
+    public void emitIntRet(Register a) {
+        emitMove(false, AMD64.rax, a);        // MOV eax, ...
+        emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp
+        emitByte(0x58 | AMD64.rbp.encoding);  // POP rbp
+        emitByte(0xC3);                       // RET
+    }
+
+    public void emitPointerRet(Register a) {
+        emitMove(true, AMD64.rax, a);         // MOV rax, ...
+        emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp
+        emitByte(0x58 | AMD64.rbp.encoding);  // POP rbp
+        emitByte(0xC3);                       // RET
+    }
+
+    public void emitTrap(DebugInfo info) {
+        result.recordInfopoint(position(), info, InfopointReason.IMPLICIT_EXCEPTION);
+        // MOV rax, [0]
+        emitByte(0x8B);
+        emitByte(0x04);
+        emitByte(0x25);
+        emitInt(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jvmci/code/sparc/SPARCTestAssembler.java	Tue Dec 15 16:55:24 2015 +0100
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 compiler.jvmci.code.sparc;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CompilationResult;
+import jdk.vm.ci.code.CompilationResult.ConstantReference;
+import jdk.vm.ci.code.CompilationResult.DataSectionReference;
+import jdk.vm.ci.code.DataSection.Data;
+import jdk.vm.ci.code.DebugInfo;
+import jdk.vm.ci.code.InfopointReason;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.VMConstant;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARCKind;
+
+import compiler.jvmci.code.TestAssembler;
+
+public class SPARCTestAssembler extends TestAssembler {
+
+    private static final int MASK13 = (1 << 13) - 1;
+
+    public SPARCTestAssembler(CompilationResult result, CodeCacheProvider codeCache) {
+        super(result, codeCache, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7);
+    }
+
+    private void emitOp2(Register rd, int op2, int imm22) {
+        emitInt((0b00 << 30) | (rd.encoding << 25) | (op2 << 22) | imm22);
+    }
+
+    private void emitOp3(int op, Register rd, int op3, Register rs1, Register rs2) {
+        emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | rs2.encoding);
+    }
+
+    private void emitOp3(int op, Register rd, int op3, Register rs1, int simm13) {
+        emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | (1 << 13) | (simm13 & MASK13));
+    }
+
+    private void emitNop() {
+        emitInt(1 << 24);
+    }
+
+    public void emitPrologue() {
+        emitOp3(0b10, SPARC.sp, 0b111100, SPARC.sp, -SPARC.REGISTER_SAFE_AREA_SIZE); // SAVE sp, -128, sp
+    }
+
+    @Override
+    public void finish() {
+        frameSize += SPARC.REGISTER_SAFE_AREA_SIZE;
+        super.finish();
+    }
+
+    public void emitGrowStack(int size) {
+        emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, size); // SUB sp, size, sp
+    }
+
+    public Register emitIntArg0() {
+        return SPARC.i0;
+    }
+
+    public Register emitIntArg1() {
+        return SPARC.i1;
+    }
+
+    public Register emitLoadInt(int c) {
+        Register ret = newRegister();
+        int hi = c >>> 10;
+        int lo = c & ((1 << 10) - 1);
+        if (hi == 0) {
+            emitOp3(0b10, ret, 0b000010, SPARC.g0, lo); // OR g0, lo, ret
+        } else {
+            emitOp2(ret, 0b100, hi);                    // SETHI hi, ret
+            if (lo != 0) {
+                emitOp3(0b10, ret, 0b000010, ret, lo);  // OR ret, lo, ret
+            }
+        }
+        return ret;
+    }
+
+    public Register emitLoadLong(long c) {
+        if ((c & 0xFFFFFFFF) == c) {
+            return emitLoadInt((int) c);
+        } else {
+            Data data = codeCache.createDataItem(JavaConstant.forLong(c));
+            DataSectionReference ref = result.getDataSection().insertData(data);
+            return emitLoadPointer(ref);
+        }
+    }
+
+    private void emitPatchableSethi(Register ret, boolean wide) {
+        int startPos = position();
+        emitOp2(ret, 0b100, 0);              // SETHI 0, ret
+        if (wide) {
+            // pad for later patching
+            while (position() < (startPos + 28)) {
+                emitNop();
+            }
+        }
+    }
+
+    public Register emitLoadFloat(float c) {
+        Data data = codeCache.createDataItem(JavaConstant.forFloat(c));
+        DataSectionReference ref = result.getDataSection().insertData(data);
+
+        Register ptr = newRegister();
+        result.recordDataPatch(position(), ref);
+        emitPatchableSethi(ptr, true);
+        emitOp3(0b11, SPARC.f0, 0b100000, ptr, 0); // LDF [ptr+0], f0
+        return SPARC.f0;
+    }
+
+    public Register emitLoadPointer(HotSpotConstant c) {
+        Register ret = newRegister();
+        result.recordDataPatch(position(), new ConstantReference((VMConstant) c));
+
+        emitPatchableSethi(ret, !c.isCompressed());
+        emitOp3(0b10, ret, 0b000010, ret, 0); // OR ret, 0, ret
+
+        return ret;
+    }
+
+    public Register emitLoadPointer(DataSectionReference ref) {
+        Register ret = newRegister();
+        result.recordDataPatch(position(), ref);
+        emitPatchableSethi(ret, true);
+        emitOp3(0b11, ret, 0b001011, ret, 0); // LDX [ret+0], ret
+        return ret;
+    }
+
+    public Register emitLoadNarrowPointer(DataSectionReference ref) {
+        Register ret = newRegister();
+        result.recordDataPatch(position(), ref);
+        emitPatchableSethi(ret, true);
+        emitOp3(0b11, ret, 0b000000, ret, 0); // LDUW [ret+0], ret
+        return ret;
+    }
+
+    public Register emitLoadPointer(Register b, int offset) {
+        Register ret = newRegister();
+        emitOp3(0b11, ret, 0b001011, b, offset); // LDX [b+offset], ret
+        return ret;
+    }
+
+    public StackSlot emitIntToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.value(SPARCKind.WORD));
+        emitOp3(0b11, a, 0b000100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STW a, [fp+offset]
+        return ret;
+    }
+
+    public StackSlot emitLongToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.value(SPARCKind.XWORD));
+        emitOp3(0b11, a, 0b001110, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STX a, [fp+offset]
+        return ret;
+    }
+
+    public StackSlot emitFloatToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.value(SPARCKind.SINGLE));
+        emitOp3(0b11, a, 0b100100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STF a, [fp+offset]
+        return ret;
+    }
+
+    public StackSlot emitPointerToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.reference(SPARCKind.XWORD));
+        emitOp3(0b11, a, 0b001110, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STX a, [fp+offset]
+        return ret;
+    }
+
+    public StackSlot emitNarrowPointerToStack(Register a) {
+        StackSlot ret = newStackSlot(LIRKind.reference(SPARCKind.WORD));
+        emitOp3(0b11, a, 0b000100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STW a, [fp+offset]
+        return ret;
+    }
+
+    public Register emitUncompressPointer(Register compressed, long base, int shift) {
+        Register ret;
+        if (shift > 0) {
+            ret = newRegister();
+            emitOp3(0b10, ret, 0b100101, compressed, shift); // SLL compressed, shift, ret
+        } else {
+            ret = compressed;
+        }
+        if (base == 0) {
+            return ret;
+        } else {
+            Register b = emitLoadLong(base);
+            emitOp3(0b10, b, 0b00000, ret, b); // ADD b, ret, b
+            return b;
+        }
+    }
+
+    public Register emitIntAdd(Register a, Register b) {
+        Register ret = newRegister();
+        emitOp3(0b10, ret, 0b00000, a, b); // ADD a, b, ret
+        return ret;
+    }
+
+    private void emitMove(Register to, Register from) {
+        if (to != from) {
+            emitOp3(0b10, to, 0b000010, from, SPARC.g0); // OR from, g0, to
+        }
+    }
+
+    public void emitIntRet(Register a) {
+        emitPointerRet(a);
+    }
+
+    public void emitPointerRet(Register a) {
+        emitMove(SPARC.i0, a);
+        emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8);        // JMPL [i7+8], g0
+        emitOp3(0b10, SPARC.g0, 0b111101, SPARC.g0, SPARC.g0); // RESTORE g0, g0, g0
+    }
+
+    public void emitTrap(DebugInfo info) {
+        result.recordInfopoint(position(), info, InfopointReason.IMPLICIT_EXCEPTION);
+        emitOp3(0b11, SPARC.g0, 0b001011, SPARC.g0, 0); // LDX [g0+0], g0
+    }
+}