8159368: [JVMCI] SPARCHotSpotRegisterConfig.callingConvention gives incorrect calling convention for native calls containing fp args
authorsanzinger
Tue, 12 Jul 2016 20:42:46 +0000
changeset 40060 0e7ca474ea35
parent 40059 c2304140ed64
child 40061 8df4c4a20902
8159368: [JVMCI] SPARCHotSpotRegisterConfig.callingConvention gives incorrect calling convention for native calls containing fp args Reviewed-by: kvn, iveresov
hotspot/make/test/JtregNative.gmk
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java
hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java
hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java
hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/sparc/SPARCTestAssembler.java
--- a/hotspot/make/test/JtregNative.gmk	Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/make/test/JtregNative.gmk	Tue Jul 12 20:42:46 2016 +0000
@@ -52,6 +52,7 @@
     $(HOTSPOT_TOPDIR)/test/compiler/calls \
     $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
     $(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \
+    $(HOTSPOT_TOPDIR)/test/compiler/jvmci/jdk.vm.ci.code.test \
     #
 
 # Add conditional directories here when needed.
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Tue Jul 12 20:42:46 2016 +0000
@@ -26,17 +26,41 @@
 import static jdk.vm.ci.meta.Value.ILLEGAL;
 import static jdk.vm.ci.sparc.SPARC.REGISTER_SAFE_AREA_SIZE;
 import static jdk.vm.ci.sparc.SPARC.d0;
+import static jdk.vm.ci.sparc.SPARC.d10;
+import static jdk.vm.ci.sparc.SPARC.d12;
+import static jdk.vm.ci.sparc.SPARC.d14;
+import static jdk.vm.ci.sparc.SPARC.d16;
+import static jdk.vm.ci.sparc.SPARC.d18;
 import static jdk.vm.ci.sparc.SPARC.d2;
+import static jdk.vm.ci.sparc.SPARC.d20;
+import static jdk.vm.ci.sparc.SPARC.d22;
+import static jdk.vm.ci.sparc.SPARC.d24;
+import static jdk.vm.ci.sparc.SPARC.d26;
+import static jdk.vm.ci.sparc.SPARC.d28;
+import static jdk.vm.ci.sparc.SPARC.d30;
 import static jdk.vm.ci.sparc.SPARC.d4;
 import static jdk.vm.ci.sparc.SPARC.d6;
+import static jdk.vm.ci.sparc.SPARC.d8;
 import static jdk.vm.ci.sparc.SPARC.f0;
 import static jdk.vm.ci.sparc.SPARC.f1;
+import static jdk.vm.ci.sparc.SPARC.f11;
+import static jdk.vm.ci.sparc.SPARC.f13;
+import static jdk.vm.ci.sparc.SPARC.f15;
+import static jdk.vm.ci.sparc.SPARC.f17;
+import static jdk.vm.ci.sparc.SPARC.f19;
 import static jdk.vm.ci.sparc.SPARC.f2;
+import static jdk.vm.ci.sparc.SPARC.f21;
+import static jdk.vm.ci.sparc.SPARC.f23;
+import static jdk.vm.ci.sparc.SPARC.f25;
+import static jdk.vm.ci.sparc.SPARC.f27;
+import static jdk.vm.ci.sparc.SPARC.f29;
 import static jdk.vm.ci.sparc.SPARC.f3;
+import static jdk.vm.ci.sparc.SPARC.f31;
 import static jdk.vm.ci.sparc.SPARC.f4;
 import static jdk.vm.ci.sparc.SPARC.f5;
 import static jdk.vm.ci.sparc.SPARC.f6;
 import static jdk.vm.ci.sparc.SPARC.f7;
+import static jdk.vm.ci.sparc.SPARC.f9;
 import static jdk.vm.ci.sparc.SPARC.g0;
 import static jdk.vm.ci.sparc.SPARC.g2;
 import static jdk.vm.ci.sparc.SPARC.g6;
@@ -95,11 +119,6 @@
 
     private final RegisterAttributes[] attributesMap;
 
-    /**
-     * Does native code (C++ code) spill arguments in registers to the parent frame?
-     */
-    private final boolean addNativeRegisterArgumentSlots;
-
     @Override
     public RegisterArray getAllocatableRegisters() {
         return allocatable;
@@ -124,10 +143,18 @@
     private final RegisterArray cpuCallerParameterRegisters = new RegisterArray(o0, o1, o2, o3, o4, o5);
     private final RegisterArray cpuCalleeParameterRegisters = new RegisterArray(i0, i1, i2, i3, i4, i5);
 
-    private final RegisterArray fpuFloatParameterRegisters = new RegisterArray(f0, f1, f2, f3, f4, f5, f6, f7);
-    private final RegisterArray fpuDoubleParameterRegisters = new RegisterArray(d0, null, d2, null, d4, null, d6, null);
+    private final RegisterArray fpuFloatJavaParameterRegisters = new RegisterArray(f0, f1, f2, f3, f4, f5, f6, f7);
+    private final RegisterArray fpuDoubleJavaParameterRegisters = new RegisterArray(d0, null, d2, null, d4, null, d6, null);
 
     // @formatter:off
+    private final RegisterArray fpuFloatNativeParameterRegisters = new RegisterArray(
+                    f1,   f3,  f5,  f7,  f9, f11, f13, f15,
+                    f17, f19, f21, f23, f25, f27, f29, f31);
+
+    private final RegisterArray fpuDoubleNativeParameterRegisters = new RegisterArray(
+                     d0,  d2,  d4,  d6,  d8, d10, d12, d14,
+                    d16, d18, d20, d22, d24, d26, d28, d30);
+
     private final RegisterArray callerSaveRegisters;
 
     /**
@@ -170,7 +197,6 @@
     public SPARCHotSpotRegisterConfig(TargetDescription target, RegisterArray allocatable) {
         this.target = target;
         this.allocatable = allocatable;
-        this.addNativeRegisterArgumentSlots = false;
         HashSet<Register> callerSaveSet = new HashSet<>(target.arch.getAvailableValueRegisters().asList());
         for (Register cs : windowSaveRegisters) {
             callerSaveSet.remove(cs);
@@ -220,7 +246,7 @@
                 return hotspotType == HotSpotCallingConventionType.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters;
             case Double:
             case Float:
-                return fpuFloatParameterRegisters;
+                return fpuFloatJavaParameterRegisters;
             default:
                 throw JVMCIError.shouldNotReachHere("Unknown JavaKind " + kind);
         }
@@ -233,48 +259,77 @@
         int currentGeneral = 0;
         int currentFloating = 0;
         int currentStackOffset = 0;
+        boolean isNative = type == HotSpotCallingConventionType.NativeCall;
 
         for (int i = 0; i < parameterTypes.length; i++) {
             final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind();
-
-            switch (kind) {
-                case Byte:
-                case Boolean:
-                case Short:
-                case Char:
-                case Int:
-                case Long:
-                case Object:
-                    if (currentGeneral < generalParameterRegisters.size()) {
-                        Register register = generalParameterRegisters.get(currentGeneral++);
-                        locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
-                    }
-                    break;
-                case Double:
-                    if (currentFloating < fpuFloatParameterRegisters.size()) {
-                        if (currentFloating % 2 != 0) {
-                            // Make register number even to be a double reg
-                            currentFloating++;
+            if (isNative) {
+                RegisterArray registerSet;
+                switch (kind) {
+                    case Byte:
+                    case Boolean:
+                    case Short:
+                    case Char:
+                    case Int:
+                    case Long:
+                    case Object:
+                        registerSet = generalParameterRegisters;
+                        break;
+                    case Double:
+                        registerSet = fpuDoubleNativeParameterRegisters;
+                        break;
+                    case Float:
+                        registerSet = fpuFloatNativeParameterRegisters;
+                        break;
+                    default:
+                        throw JVMCIError.shouldNotReachHere();
+                }
+                if (i < registerSet.size()) {
+                    locations[i] = registerSet.get(i).asValue(valueKindFactory.getValueKind(kind));
+                    currentStackOffset += target.arch.getWordSize();
+                }
+            } else {
+                switch (kind) {
+                    case Byte:
+                    case Boolean:
+                    case Short:
+                    case Char:
+                    case Int:
+                    case Long:
+                    case Object:
+                        if (currentGeneral < generalParameterRegisters.size()) {
+                            Register register = generalParameterRegisters.get(currentGeneral++);
+                            locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
                         }
-                        Register register = fpuDoubleParameterRegisters.get(currentFloating);
-                        currentFloating += 2; // Only every second is a double register
-                        locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
-                    }
-                    break;
-                case Float:
-                    if (currentFloating < fpuFloatParameterRegisters.size()) {
-                        Register register = fpuFloatParameterRegisters.get(currentFloating++);
-                        locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
-                    }
-                    break;
-                default:
-                    throw JVMCIError.shouldNotReachHere();
+                        break;
+                    case Double:
+                        if (currentFloating < fpuFloatJavaParameterRegisters.size()) {
+                            if (currentFloating % 2 != 0) {
+                                // Make register number even to be a double reg
+                                currentFloating++;
+                            }
+                            Register register = fpuDoubleJavaParameterRegisters.get(currentFloating);
+                            currentFloating += 2; // Only every second is a double register
+                            locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
+                        }
+                        break;
+                    case Float:
+                        if (currentFloating < fpuFloatJavaParameterRegisters.size()) {
+                            Register register = fpuFloatJavaParameterRegisters.get(currentFloating++);
+                            locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
+                        }
+                        break;
+                    default:
+                        throw JVMCIError.shouldNotReachHere();
+                }
             }
 
             if (locations[i] == null) {
                 ValueKind<?> valueKind = valueKindFactory.getValueKind(kind);
-                // Stack slot is always aligned to its size in bytes but minimum wordsize
                 int typeSize = valueKind.getPlatformKind().getSizeInBytes();
+                if (isNative) {
+                    currentStackOffset += target.arch.getWordSize() - typeSize;
+                }
                 currentStackOffset = roundUp(currentStackOffset, typeSize);
                 int slotOffset = currentStackOffset + REGISTER_SAFE_AREA_SIZE;
                 locations[i] = StackSlot.get(valueKind, slotOffset, !type.out);
@@ -284,15 +339,7 @@
 
         JavaKind returnKind = returnType == null ? Void : returnType.getJavaKind();
         AllocatableValue returnLocation = returnKind == Void ? ILLEGAL : getReturnRegister(returnKind, type).asValue(valueKindFactory.getValueKind(returnKind.getStackKind()));
-
-        int outArgSpillArea;
-        if (type == HotSpotCallingConventionType.NativeCall && addNativeRegisterArgumentSlots) {
-            // Space for native callee which may spill our outgoing arguments
-            outArgSpillArea = Math.min(locations.length, generalParameterRegisters.size()) * target.wordSize;
-        } else {
-            outArgSpillArea = 0;
-        }
-        return new CallingConvention(currentStackOffset + outArgSpillArea, returnLocation, locations);
+        return new CallingConvention(currentStackOffset, returnLocation, locations);
     }
 
     private static int roundUp(int number, int mod) {
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java	Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java	Tue Jul 12 20:42:46 2016 +0000
@@ -23,10 +23,12 @@
 
 package jdk.vm.ci.code.test;
 
+import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.DebugInfo;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.ValueKindFactory;
 import jdk.vm.ci.code.site.Call;
 import jdk.vm.ci.code.site.ConstantReference;
 import jdk.vm.ci.code.site.DataPatch;
@@ -41,6 +43,7 @@
 import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
 import jdk.vm.ci.hotspot.HotSpotConstant;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Assumptions.Assumption;
 import jdk.vm.ci.meta.InvokeTarget;
 import jdk.vm.ci.meta.JavaKind;
@@ -145,6 +148,11 @@
     public abstract StackSlot emitFloatToStack(Register a);
 
     /**
+     * Emit code to store a double-precision float from a register to a new stack slot.
+     */
+    public abstract StackSlot emitDoubleToStack(Register a);
+
+    /**
      * Emit code to store a wide pointer from a register to a new stack slot.
      */
     public abstract StackSlot emitPointerToStack(Register a);
@@ -165,6 +173,11 @@
     public abstract void emitIntRet(Register a);
 
     /**
+     * Emit code to return from a function, returning a single precision float.
+     */
+    public abstract void emitFloatRet(Register a);
+
+    /**
      * Emit code to return from a function, returning a wide oop pointer.
      */
     public abstract void emitPointerRet(Register a);
@@ -193,7 +206,13 @@
 
     private StackSlot deoptRescue;
 
-    private static class TestValueKind extends ValueKind<TestValueKind> {
+    public ValueKindFactory<TestValueKind> valueKindFactory = new ValueKindFactory<TestAssembler.TestValueKind>() {
+        public TestValueKind getValueKind(JavaKind javaKind) {
+            return (TestValueKind) TestAssembler.this.getValueKind(javaKind);
+        }
+    };
+
+    static class TestValueKind extends ValueKind<TestValueKind> {
 
         TestValueKind(PlatformKind kind) {
             super(kind);
@@ -340,6 +359,11 @@
             data.putFloat(f);
         }
 
+        public void emitDouble(double f) {
+            ensureSize(data.position() + 8);
+            data.putDouble(f);
+        }
+
         public void align(int alignment) {
             int pos = data.position();
             int misaligned = pos % alignment;
@@ -353,4 +377,27 @@
             return Arrays.copyOf(data.array(), data.position());
         }
     }
+
+    /**
+     * Loads a primitive into the Allocatable <code>av</code>. Implementors may only implement
+     * primitive types.
+     */
+    public abstract void emitLoad(AllocatableValue av, Object prim);
+
+    /**
+     * Emit a call to a fixed address <code>addr</code>
+     */
+    public abstract void emitCall(long addr);
+
+    /**
+     * Emit code which is necessary to call a method with {@link CallingConvention} <code>cc</code>
+     * and arguments <coe>prim</code>.
+     */
+    public abstract void emitCallPrologue(CallingConvention cc, Object... prim);
+
+    /**
+     * Emit code which is necessary after calling a method with CallingConvention <code>cc</code>.
+     */
+    public abstract void emitCallEpilogue(CallingConvention cc);
+
 }
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java	Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java	Tue Jul 12 20:42:46 2016 +0000
@@ -23,11 +23,15 @@
 
 package jdk.vm.ci.code.test.amd64;
 
+import static jdk.vm.ci.amd64.AMD64.xmm0;
+
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.DebugInfo;
 import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.site.ConstantReference;
 import jdk.vm.ci.code.site.DataSectionReference;
@@ -36,6 +40,7 @@
 import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
 import jdk.vm.ci.hotspot.HotSpotConstant;
 import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
+import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.VMConstant;
 
@@ -116,6 +121,10 @@
     @Override
     public Register emitLoadInt(int c) {
         Register ret = newRegister();
+        return emitLoadInt(ret, c);
+    }
+
+    public Register emitLoadInt(Register ret, int c) {
         emitREX(false, 0, 0, ret.encoding);
         code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32
         code.emitInt(c);
@@ -125,6 +134,10 @@
     @Override
     public Register emitLoadLong(long c) {
         Register ret = newRegister();
+        return emitLoadLong(ret, c);
+    }
+
+    public Register emitLoadLong(Register ret, long c) {
         emitREX(true, 0, 0, ret.encoding);
         code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r64, imm64
         code.emitLong(c);
@@ -133,12 +146,16 @@
 
     @Override
     public Register emitLoadFloat(float c) {
+        Register ret = AMD64.xmm0;
+        return emitLoadFloat(ret, c);
+    }
+
+    public Register emitLoadFloat(Register ret, float c) {
         DataSectionReference ref = new DataSectionReference();
         ref.setOffset(data.position());
         data.emitFloat(c);
 
         recordDataPatchInCode(ref);
-        Register ret = AMD64.xmm0;
         emitREX(false, ret.encoding, 0, 0);
         code.emitByte(0xF3);
         code.emitByte(0x0F);
@@ -148,6 +165,26 @@
         return ret;
     }
 
+    public Register emitLoadDouble(double c) {
+        Register ret = AMD64.xmm0;
+        return emitLoadDouble(ret, c);
+    }
+
+    public Register emitLoadDouble(Register ret, double c) {
+        DataSectionReference ref = new DataSectionReference();
+        ref.setOffset(data.position());
+        data.emitDouble(c);
+
+        recordDataPatchInCode(ref);
+        emitREX(false, ret.encoding, 0, 0);
+        code.emitByte(0xF2);
+        code.emitByte(0x0F);
+        code.emitByte(0x10);                               // MOVSD xmm1, xmm2/m32
+        code.emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // xmm, [rip+offset]
+        code.emitInt(0xDEADDEAD);
+        return ret;
+    }
+
     @Override
     public Register emitLoadPointer(HotSpotConstant c) {
         recordDataPatchInCode(new ConstantReference((VMConstant) c));
@@ -192,6 +229,10 @@
     @Override
     public StackSlot emitIntToStack(Register a) {
         StackSlot ret = newStackSlot(AMD64Kind.DWORD);
+        return emitIntToStack(ret, a);
+    }
+
+    public StackSlot emitIntToStack(StackSlot ret, Register a) {
         // MOV r/m32,r32
         emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16);
         return ret;
@@ -200,6 +241,10 @@
     @Override
     public StackSlot emitLongToStack(Register a) {
         StackSlot ret = newStackSlot(AMD64Kind.QWORD);
+        return emitLongToStack(ret, a);
+    }
+
+    public StackSlot emitLongToStack(StackSlot ret, Register a) {
         // MOV r/m64,r64
         emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16);
         return ret;
@@ -208,12 +253,40 @@
     @Override
     public StackSlot emitFloatToStack(Register a) {
         StackSlot ret = newStackSlot(AMD64Kind.SINGLE);
+        return emitFloatToStack(ret, a);
+    }
+
+    public StackSlot emitFloatToStack(StackSlot ret, Register a) {
         emitREX(false, a.encoding, 0, 0);
         code.emitByte(0xF3);
         code.emitByte(0x0F);
         code.emitByte(0x11);                               // MOVSS xmm2/m32, xmm1
         code.emitByte(0x85 | ((a.encoding & 0x7) << 3));   // [rbp+offset]
-        code.emitInt(ret.getRawOffset() + 16);
+        if (ret.getRawOffset() < 0) {
+            code.emitInt(ret.getRawOffset() + 16);
+        } else {
+            code.emitInt(-(frameSize - ret.getRawOffset()) + 16);
+        }
+        return ret;
+    }
+
+    @Override
+    public StackSlot emitDoubleToStack(Register a) {
+        StackSlot ret = newStackSlot(AMD64Kind.DOUBLE);
+        return emitDoubleToStack(ret, a);
+    }
+
+    public StackSlot emitDoubleToStack(StackSlot ret, Register a) {
+        emitREX(false, a.encoding, 0, 0);
+        code.emitByte(0xF2);
+        code.emitByte(0x0F);
+        code.emitByte(0x11);                               // MOVSD xmm2/m32, xmm1
+        code.emitByte(0x85 | ((a.encoding & 0x7) << 3));   // [rbp+offset]
+        if (ret.getRawOffset() < 0) {
+            code.emitInt(ret.getRawOffset() + 16);
+        } else {
+            code.emitInt(-(frameSize - ret.getRawOffset()) + 16);
+        }
         return ret;
     }
 
@@ -269,6 +342,14 @@
     }
 
     @Override
+    public void emitFloatRet(Register a) {
+        assert a == xmm0 : "Unimplemented move " + a;
+        emitMove(true, AMD64.rsp, AMD64.rbp);      // MOV rsp, rbp
+        code.emitByte(0x58 | AMD64.rbp.encoding);  // POP rbp
+        code.emitByte(0xC3);                       // RET
+    }
+
+    @Override
     public void emitPointerRet(Register a) {
         emitMove(true, AMD64.rax, a);              // MOV rax, ...
         emitMove(true, AMD64.rsp, AMD64.rbp);      // MOV rsp, rbp
@@ -285,4 +366,64 @@
         code.emitByte(0x25);
         code.emitInt(0);
     }
+
+    @Override
+    public void emitLoad(AllocatableValue av, Object prim) {
+        if (av instanceof RegisterValue) {
+            Register reg = ((RegisterValue) av).getRegister();
+            if (prim instanceof Float) {
+                emitLoadFloat(reg, (Float) prim);
+            } else if (prim instanceof Double) {
+                emitLoadDouble(reg, (Double) prim);
+            } else if (prim instanceof Integer) {
+                emitLoadInt(reg, (Integer) prim);
+            } else if (prim instanceof Long) {
+                emitLoadLong(reg, (Long) prim);
+            }
+        } else if (av instanceof StackSlot) {
+            StackSlot slot = (StackSlot) av;
+            if (prim instanceof Float) {
+                emitFloatToStack(slot, emitLoadFloat((Float) prim));
+            } else if (prim instanceof Double) {
+                emitDoubleToStack(slot, emitLoadDouble((Double) prim));
+            } else if (prim instanceof Integer) {
+                emitIntToStack(slot, emitLoadInt((Integer) prim));
+            } else if (prim instanceof Long) {
+                emitLongToStack(slot, emitLoadLong((Long) prim));
+            }
+            assert false : "Unimplemented";
+        } else {
+            throw new IllegalArgumentException("Unknown value " + av);
+        }
+    }
+
+    @Override
+    public void emitCallPrologue(CallingConvention cc, Object... prim) {
+        emitGrowStack(cc.getStackSize());
+        frameSize += cc.getStackSize();
+        AllocatableValue[] args = cc.getArguments();
+        // Do the emission in reverse, this avoids register collisons of xmm0 - which is used a
+        // scratch register when putting arguments on the stack.
+        for (int i = args.length - 1; i >= 0; i--) {
+            emitLoad(args[i], prim[i]);
+        }
+    }
+
+    @Override
+    public void emitCall(long addr) {
+        Register target = emitLoadLong(addr);
+        code.emitByte(0xFF); // CALL r/m64
+        int enc = target.encoding;
+        if (enc >= 8) {
+            code.emitByte(0x41);
+            enc -= 8;
+        }
+        code.emitByte(0xD0 | enc);
+    }
+
+    @Override
+    public void emitCallEpilogue(CallingConvention cc) {
+        emitGrowStack(-cc.getStackSize());
+        frameSize -= cc.getStackSize();
+    }
 }
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/sparc/SPARCTestAssembler.java	Tue Jul 12 18:24:48 2016 +0300
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/sparc/SPARCTestAssembler.java	Tue Jul 12 20:42:46 2016 +0000
@@ -23,9 +23,12 @@
 
 package jdk.vm.ci.code.test.sparc;
 
+import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.DebugInfo;
 import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
+import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.site.ConstantReference;
 import jdk.vm.ci.code.site.DataSectionReference;
@@ -36,6 +39,7 @@
 import jdk.vm.ci.hotspot.HotSpotConstant;
 import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.VMConstant;
 import jdk.vm.ci.sparc.SPARC;
@@ -44,6 +48,9 @@
 public class SPARCTestAssembler extends TestAssembler {
 
     private static final int MASK13 = (1 << 13) - 1;
+    private static final Register scratchRegister = SPARC.g5;
+    private static final Register floatScratch = SPARC.f30;
+    private static final Register doubleScratch = SPARC.d62;
 
     public SPARCTestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) {
         super(codeCache, config, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7);
@@ -136,7 +143,7 @@
         return ret;
     }
 
-    private void loadIntToRegister(int c, Register ret) {
+    private Register loadIntToRegister(int c, Register ret) {
         int hi = c >>> 10;
         int lo = c & ((1 << 10) - 1);
         if (hi == 0) {
@@ -147,6 +154,7 @@
                 emitOp3(0b10, ret, 0b000010, ret, lo);  // OR ret, lo, ret
             }
         }
+        return ret;
     }
 
     @Override
@@ -164,12 +172,13 @@
         emitLoadPointerToRegister(ref, ret);
     }
 
-    public void emitLoadLongToRegister(long c, Register r) {
+    public Register emitLoadLongToRegister(long c, Register r) {
         if ((c & 0xFFFF_FFFFL) == c) {
             loadIntToRegister((int) c, r);
         } else {
             loadLongToRegister(c, r);
         }
+        return r;
     }
 
     private void emitPatchableSethi(Register ret, boolean wide) {
@@ -185,16 +194,39 @@
 
     @Override
     public Register emitLoadFloat(float c) {
+        return emitLoadFloat(SPARC.f0, c);
+    }
+
+    public Register emitLoadFloat(Register reg, float c) {
+        return emitLoadFloat(reg, c, newRegister());
+    }
+
+    public Register emitLoadFloat(Register reg, float c, Register scratch) {
         DataSectionReference ref = new DataSectionReference();
         data.align(4);
         ref.setOffset(data.position());
         data.emitFloat(c);
 
-        Register ptr = newRegister();
         recordDataPatchInCode(ref);
-        emitPatchableSethi(ptr, true);
-        emitOp3(0b11, SPARC.f0, 0b100000, ptr, 0); // LDF [ptr+0], f0
-        return SPARC.f0;
+        emitPatchableSethi(scratch, true);
+        emitOp3(0b11, reg, 0b100000, scratch, 0); // LDF [scratch+0], f0
+        return reg;
+    }
+
+    public Register emitLoadDouble(Register reg, double c) {
+        return emitLoadDouble(reg, c, newRegister());
+    }
+
+    public Register emitLoadDouble(Register reg, double c, Register scratch) {
+        DataSectionReference ref = new DataSectionReference();
+        data.align(8);
+        ref.setOffset(data.position());
+        data.emitDouble(c);
+
+        recordDataPatchInCode(ref);
+        emitPatchableSethi(scratch, true);
+        emitOp3(0b11, reg, 0b100011, scratch, 0); // LDDF [ptr+0], f0
+        return reg;
     }
 
     @Override
@@ -240,24 +272,48 @@
     @Override
     public StackSlot emitIntToStack(Register a) {
         StackSlot ret = newStackSlot(SPARCKind.WORD);
-        // STW a, [fp+offset]
+        intToStack(a, ret);
+        return ret;
+    }
+
+    public void intToStack(Register a, StackSlot ret) {
+        // STW a, [(s|f)p+offset]
         emitStore(0b000100, a, ret);
-        return ret;
     }
 
     @Override
     public StackSlot emitLongToStack(Register a) {
         StackSlot ret = newStackSlot(SPARCKind.XWORD);
-        // STX a, [sp+offset]
+        longToStack(a, ret);
+        return ret;
+    }
+
+    public void longToStack(Register a, StackSlot ret) {
+        // STX a, [(f|s)p+offset]
         emitStore(0b001110, a, ret);
-        return ret;
     }
 
     @Override
     public StackSlot emitFloatToStack(Register a) {
         StackSlot ret = newStackSlot(SPARCKind.SINGLE);
+        floatToStack(a, ret);
+        return ret;
+    }
+
+    public void floatToStack(Register a, StackSlot ret) {
         // STF a, [fp+offset]
         emitStore(0b100100, a, ret);
+    }
+
+    @Override
+    public StackSlot emitDoubleToStack(Register a) {
+        StackSlot ret = newStackSlot(SPARCKind.DOUBLE);
+        return doubleToStack(a, ret);
+    }
+
+    public StackSlot doubleToStack(Register a, StackSlot ret) {
+        // STD a, [(s|f)p+offset]
+        emitStore(0b100111, a, ret);
         return ret;
     }
 
@@ -278,16 +334,22 @@
     }
 
     private void emitStore(int op3, Register a, StackSlot ret) {
+        Register base;
+        if (ret.getRawOffset() < 0) {
+            base = SPARC.fp;
+        } else {
+            base = SPARC.sp;
+        }
         int offset = ret.getRawOffset() + SPARC.STACK_BIAS;
         if (isSimm(offset, 13)) {
             // op3 a, [sp+offset]
-            emitOp3(0b11, a, op3, SPARC.fp, offset);
+            emitOp3(0b11, a, op3, base, offset);
         } else {
             assert a != SPARC.g3;
             Register r = SPARC.g3;
             loadLongToRegister(offset, r);
             // op3 a, [sp+g3]
-            emitOp3(0b11, a, op3, SPARC.fp, r);
+            emitOp3(0b11, a, op3, base, r);
         }
     }
 
@@ -328,6 +390,13 @@
     }
 
     @Override
+    public void emitFloatRet(Register a) {
+        assert a == SPARC.f0 : "Unimplemented";
+        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
+    }
+
+    @Override
     public void emitPointerRet(Register a) {
         emitMove(SPARC.i0, a);
         emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8);        // JMPL [i7+8], g0
@@ -349,4 +418,57 @@
         }
         return super.emitDataItem(c);
     }
+
+    @Override
+    public void emitCall(long addr) {
+        Register dst = emitLoadLong(addr);
+        emitOp3(0b10, SPARC.o7, 0b111000, dst, 0);        // JMPL [dst+0], o7
+        emitNop();
+    }
+
+    @Override
+    public void emitLoad(AllocatableValue av, Object prim) {
+        if (av instanceof RegisterValue) {
+            Register reg = ((RegisterValue) av).getRegister();
+            RegisterCategory cat = reg.getRegisterCategory();
+            if (cat.equals(SPARC.FPUs)) {
+                emitLoadFloat(reg, (Float) prim, scratchRegister);
+            } else if (cat.equals(SPARC.FPUd)) {
+                emitLoadDouble(reg, (Double) prim, scratchRegister);
+            } else if (prim instanceof Integer) {
+                loadIntToRegister((Integer) prim, reg);
+            } else if (prim instanceof Long) {
+                loadLongToRegister((Long) prim, reg);
+            }
+        } else if (av instanceof StackSlot) {
+            StackSlot slot = (StackSlot) av;
+            if (prim instanceof Float) {
+                floatToStack(emitLoadFloat(floatScratch, (Float) prim, scratchRegister), slot);
+            } else if (prim instanceof Double) {
+                doubleToStack(emitLoadDouble(doubleScratch, (Double) prim, scratchRegister), slot);
+            } else if (prim instanceof Integer) {
+                intToStack(loadIntToRegister((Integer) prim, scratchRegister), slot);
+            } else if (prim instanceof Long) {
+                longToStack(emitLoadLongToRegister((Long) prim, scratchRegister), slot);
+            }
+        } else {
+            throw new IllegalArgumentException("Unknown value " + av);
+        }
+    }
+
+    @Override
+    public void emitCallEpilogue(CallingConvention cc) {
+        // Nothing to do here.
+    }
+
+    @Override
+    public void emitCallPrologue(CallingConvention cc, Object... prim) {
+        emitGrowStack(cc.getStackSize());
+        frameSize += cc.getStackSize();
+        AllocatableValue[] args = cc.getArguments();
+        for (int i = 0; i < args.length; i++) {
+            emitLoad(args[i], prim[i]);
+        }
+    }
+
 }