changeset 9463:902a974d55c8

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 30 Apr 2013 23:24:25 +0200
parents 861a9e0aba38 (current diff) 56c12e0c15c1 (diff)
children b5d83338286f
files graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/IdentityHashCodeStub.java src/cpu/x86/vm/graalRuntime_x86.cpp src/share/vm/graal/graalCompilerToVM.cpp src/share/vm/graal/graalRuntime.hpp
diffstat 20 files changed, 135 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java	Tue Apr 30 23:24:25 2013 +0200
@@ -115,5 +115,11 @@
 
     Descriptor getDescriptor();
 
-    boolean preservesRegisters();
+    /**
+     * Determines if the target routine destroys all registers.
+     * 
+     * @return {@code true} if the register allocator must save all live registers around a call to
+     *         this target
+     */
+    boolean destroysRegisters();
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue Apr 30 23:24:25 2013 +0200
@@ -413,7 +413,7 @@
      */
     boolean hasCall(int opId) {
         assert isEven(opId) : "opId not even";
-        return instructionForId(opId).hasCall();
+        return instructionForId(opId).destroysCallerSavedRegisters();
     }
 
     /**
@@ -1181,7 +1181,7 @@
                 final int opId = op.id();
 
                 // add a temp range for each register if operation destroys caller-save registers
-                if (op.hasCall()) {
+                if (op.destroysCallerSavedRegisters()) {
                     for (Register r : callerSaveRegs) {
                         if (attributes(r).isAllocatable()) {
                             addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal);
@@ -1681,7 +1681,7 @@
             // before we've consumed the inputs.
             if (op.id() < interval.currentTo()) {
                 // caller-save registers must not be included into oop-maps at calls
-                assert !op.hasCall() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten";
+                assert !op.destroysCallerSavedRegisters() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten";
 
                 frameMap.setReference(interval.location(), registerRefMap, frameRefMap);
 
@@ -1703,7 +1703,7 @@
     }
 
     private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
-        BitSet registerRefMap = op.hasCall() ? null : frameMap.initRegisterRefMap();
+        BitSet registerRefMap = op.destroysCallerSavedRegisters() ? null : frameMap.initRegisterRefMap();
         BitSet frameRefMap = frameMap.initFrameRefMap();
         computeOopMap(iw, op, registerRefMap, frameRefMap);
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java	Tue Apr 30 23:24:25 2013 +0200
@@ -248,7 +248,7 @@
             // check if input operands are correct
             op.forEachInput(useProc);
             // invalidate all caller save registers at calls
-            if (op.hasCall()) {
+            if (op.destroysCallerSavedRegisters()) {
                 for (Register r : allocator.frameMap.registerConfig.getCallerSaveRegisters()) {
                     statePut(inputState, r.asValue(), null);
                 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Tue Apr 30 23:24:25 2013 +0200
@@ -22,23 +22,21 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
 @Opcode("DEOPT")
 final class AMD64DeoptimizeOp extends AMD64LIRInstruction {
 
-    public static final Descriptor DEOPTIMIZE = new Descriptor("deoptimize", true, void.class);
-
     private DeoptimizationAction action;
     private DeoptimizationReason reason;
     @State private LIRFrameState info;
@@ -54,6 +52,6 @@
         HotSpotGraalRuntime runtime = graalRuntime();
         Register thread = runtime.getRuntime().threadRegister();
         masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
-        AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE), null, false, info);
+        AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP), null, false, info);
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Apr 30 23:24:25 2013 +0200
@@ -34,7 +34,6 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
@@ -45,8 +44,8 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 import com.oracle.graal.lir.StandardOp.ParametersOp;
-import com.oracle.graal.lir.LIRInstruction.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
@@ -59,9 +58,6 @@
 public class AMD64HotSpotBackend extends HotSpotBackend {
 
     private static final Unsafe unsafe = Unsafe.getUnsafe();
-    public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class);
-    public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class);
-    public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class);
 
     public AMD64HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) {
         super(runtime, target);
@@ -100,13 +96,21 @@
 
     class HotSpotFrameContext implements FrameContext {
 
+        final boolean isStub;
+
+        HotSpotFrameContext(boolean isStub) {
+            this.isStub = isStub;
+        }
+
         @Override
         public void enter(TargetMethodAssembler tasm) {
             FrameMap frameMap = tasm.frameMap;
             int frameSize = frameMap.frameSize();
 
             AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm;
-            emitStackOverflowCheck(tasm, false);
+            if (!isStub) {
+                emitStackOverflowCheck(tasm, false);
+            }
             asm.decrementq(rsp, frameSize);
             if (GraalOptions.ZapStackOnMethodEntry) {
                 final int intSize = 4;
@@ -156,16 +160,16 @@
         LIR lir = gen.lir;
         boolean omitFrame = CanOmitFrame && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame();
 
+        Stub stub = runtime().asStub(lirGen.method());
         AbstractAssembler masm = createAssembler(frameMap);
-        HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext();
+        HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext(stub != null);
         TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult);
         tasm.setFrameSize(frameMap.frameSize());
         StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot;
-        if (deoptimizationRescueSlot != null) {
+        if (deoptimizationRescueSlot != null && stub == null) {
             tasm.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
         }
 
-        Stub stub = runtime().asStub(lirGen.method());
         if (stub != null) {
 
             final Set<Register> definedRegisters = gatherDefinedRegisters(lir);
@@ -244,8 +248,8 @@
         // Emit code for the LIR
         lirGen.lir.emitCode(tasm);
 
-        boolean frameOmitted = tasm.frameContext == null;
-        if (!frameOmitted) {
+        HotSpotFrameContext frameContext = (HotSpotFrameContext) tasm.frameContext;
+        if (frameContext != null && !frameContext.isStub) {
             tasm.recordMark(Marks.MARK_EXCEPTION_HANDLER_ENTRY);
             AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(EXCEPTION_HANDLER), null, false, null);
             tasm.recordMark(Marks.MARK_DEOPT_HANDLER_ENTRY);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Tue Apr 30 23:24:25 2013 +0200
@@ -24,8 +24,8 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.amd64.AMD64DeoptimizeOp.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -66,6 +66,6 @@
         HotSpotGraalRuntime runtime = graalRuntime();
         Register thread = runtime.getRuntime().threadRegister();
         masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason));
-        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE));
+        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Tue Apr 30 23:24:25 2013 +0200
@@ -24,8 +24,6 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.compiler.amd64.AMD64LIRGenerator.*;
-import static com.oracle.graal.hotspot.amd64.AMD64DeoptimizeOp.*;
-import static com.oracle.graal.hotspot.amd64.AMD64HotSpotBackend.*;
 import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*;
 import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*;
 import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*;
@@ -61,10 +59,6 @@
                /*             ret */ ret(Kind.Void),
                /* arg0: exception */ rax.asValue(Kind.Object));
 
-        addRuntimeCall(DEOPTIMIZE, config.deoptimizeStub,
-                /*           temps */ null,
-                /*             ret */ ret(Kind.Void));
-
         addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub,
                 /*           temps */ new Register[]{AMD64.rax},
                 /*             ret */ ret(Kind.Float),
@@ -142,18 +136,6 @@
                 /* arg2:    key */                         word,
                 /* arg3:      r */                         word,
               /* arg4: inLength */                         Kind.Int));
-
-        addRuntimeCall(EXCEPTION_HANDLER, config.handleExceptionStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void));
-
-        addRuntimeCall(DEOPT_HANDLER, config.handleDeoptStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void));
-
-        addRuntimeCall(IC_MISS_HANDLER, config.inlineCacheMissStub,
-                /*        temps */ null,
-                /*          ret */ ret(Kind.Void));
         // @formatter:on
 
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Apr 30 23:24:25 2013 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
 
@@ -31,6 +32,26 @@
  */
 public abstract class HotSpotBackend extends Backend {
 
+    /**
+     * Descriptor for SharedRuntime::deopt_blob()->uncommon_trap().
+     */
+    public static final Descriptor UNCOMMON_TRAP = new Descriptor("deoptimize", true, void.class);
+
+    /**
+     * Descriptor for GraalRuntime::handle_exception_nofpu_id.
+     */
+    public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class);
+
+    /**
+     * Descriptor for SharedRuntime::deopt_blob()->unpack().
+     */
+    public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class);
+
+    /**
+     * Descriptor for SharedRuntime::get_ic_miss_stub().
+     */
+    public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class);
+
     public HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) {
         super(runtime, target);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java	Tue Apr 30 23:24:25 2013 +0200
@@ -111,10 +111,24 @@
         }
     }
 
+    public long getAddress() {
+        assert address != 0L : "address not yet finalized: " + this;
+        return address;
+    }
+
     @Override
-    public boolean preservesRegisters() {
-        assert address != 0;
-        return true;
+    public boolean destroysRegisters() {
+        if (isCRuntimeCall) {
+            // Even though most native ABIs define some callee saved registers,
+            // for simplicity we force the register allocator to save all live
+            // registers across a C runtime call as such calls are only made from
+            // compiled stubs which a) are slow path and b) will typically only
+            // have very few live registers across a C runtime call
+            return true;
+        }
+        // This is a call to a compiled (or assembler) stub which saves
+        // all registers (apart from its temporaries)
+        return false;
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 30 23:24:25 2013 +0200
@@ -353,7 +353,7 @@
 
     public long verifyOopStub;
     public long vmErrorStub;
-    public long deoptimizeStub;
+    public long uncommonTrapStub;
     public long unwindExceptionStub;
     public long osrMigrationEndStub;
     public long createNullPointerExceptionStub;
@@ -368,7 +368,6 @@
     public long logPrimitiveStub;
     public long logObjectStub;
     public long logPrintfStub;
-    public long stubPrintfStub;
     public int deoptReasonNone;
     public long aescryptEncryptBlockStub;
     public long aescryptDecryptBlockStub;
@@ -380,6 +379,7 @@
     public long newMultiArrayAddress;
     public long registerFinalizerAddress;
     public long threadIsInterruptedAddress;
+    public long stubPrintfAddress;
     public long identityHashCodeAddress;
 
     public int deoptReasonNullCheck;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Apr 30 23:24:25 2013 +0200
@@ -28,6 +28,7 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.IdentityHashCodeStubCall.*;
 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
@@ -217,6 +218,10 @@
                         /*             ret */ ret(Kind.Void),
                         /* arg0:      long */ javaCallingConvention(Kind.Long));
 
+        addRuntimeCall(UNCOMMON_TRAP, config.uncommonTrapStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void));
+
         addStubCall(REGISTER_FINALIZER,
                         /*             ret */ ret(Kind.Void),
                         /* arg0:    object */ javaCallingConvention(Kind.Object));
@@ -306,13 +311,12 @@
                         /* arg2:     value */                       Kind.Long,
                         /* arg3:     value */                       Kind.Long));
 
-        addRuntimeCall(STUB_PRINTF, config.stubPrintfStub,
-                        /*           temps */ null,
+        addCRuntimeCall(STUB_PRINTF_C, config.stubPrintfAddress,
                         /*             ret */ ret(Kind.Void),
-                        /* arg0:    format */ javaCallingConvention(Kind.Long,
-                        /* arg1:     value */                       Kind.Long,
-                        /* arg2:     value */                       Kind.Long,
-                        /* arg3:     value */                       Kind.Long));
+                        /* arg0:    format */ nativeCallingConvention(Kind.Long,
+                        /* arg1:     value */                         Kind.Long,
+                        /* arg2:     value */                         Kind.Long,
+                        /* arg3:     value */                         Kind.Long));
 
         addRuntimeCall(LOG_OBJECT, config.logObjectStub,
                         /*           temps */ null,
@@ -331,6 +335,18 @@
                    /* arg1: receiverThread */                         Kind.Object,
               /* arg1: clearInterrupted */                            Kind.Boolean));
 
+        addRuntimeCall(EXCEPTION_HANDLER, config.handleExceptionStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void));
+
+        addRuntimeCall(DEOPT_HANDLER, config.handleDeoptStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void));
+
+        addRuntimeCall(IC_MISS_HANDLER, config.inlineCacheMissStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void));
+
         addStubCall(IDENTITY_HASHCODE,
                         /*          ret */ ret(Kind.Int),
                         /* arg0:    obj */ javaCallingConvention(Kind.Object));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/IdentityHashCodeStub.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/IdentityHashCodeStub.java	Tue Apr 30 23:24:25 2013 +0200
@@ -46,7 +46,6 @@
 
     @Snippet
     private static int identityHashCode(Object object) {
-        printf("Calling identityHashCode\n", 0);
         int result = identityHashCodeC(IDENTITY_HASH_CODE_C, thread(), object);
         handlePendingException(false);
         return result;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Apr 30 23:24:25 2013 +0200
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.api.code.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.api.meta.MetaUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 import static com.oracle.graal.hotspot.nodes.CStringNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*;
 
@@ -32,7 +34,9 @@
 import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CompilationResult.Call;
 import com.oracle.graal.api.code.CompilationResult.DataPatch;
+import com.oracle.graal.api.code.CompilationResult.Infopoint;
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
@@ -46,7 +50,6 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
@@ -61,7 +64,8 @@
 
 /**
  * Base class for implementing some low level code providing the out-of-line slow path for a
- * snippet. A concrete stub is defined a subclass of this class.
+ * snippet. A stub may make a direct call to a HotSpot C/C++ runtime function. Stubs are installed
+ * as an instance of the C++ RuntimeStub class (as opposed to nmethod).
  * <p>
  * Implementation detail: The stub classes re-use some of the functionality for {@link Snippet}s
  * purely for convenience (e.g., can re-use the {@link ReplacementsImpl}).
@@ -130,11 +134,22 @@
         return linkage;
     }
 
-    private boolean checkCompilationResult(CompilationResult compResult) {
+    /**
+     * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub.
+     */
+    private boolean checkStubInvariants(CompilationResult compResult) {
         for (DataPatch data : compResult.getDataReferences()) {
             Constant constant = data.constant;
-            assert constant.getKind() != Kind.Object : MetaUtil.format("%h.%n(%p): ", getMethod()) + "cannot have embedded oop: " + constant;
-            assert constant.getPrimitiveAnnotation() == null : MetaUtil.format("%h.%n(%p): ", getMethod()) + "cannot have embedded metadata: " + constant;
+            assert constant.getKind() != Kind.Object : format("%h.%n(%p): ", getMethod()) + "cannot have embedded oop: " + constant;
+            assert constant.getPrimitiveAnnotation() == null : format("%h.%n(%p): ", getMethod()) + "cannot have embedded metadata: " + constant;
+        }
+        for (Infopoint infopoint : compResult.getInfopoints()) {
+            assert infopoint instanceof Call : format("%h.%n(%p): ", getMethod()) + "cannot have non-call infopoint: " + infopoint;
+            Call call = (Call) infopoint;
+            assert call.target instanceof HotSpotRuntimeCallTarget : format("%h.%n(%p): ", getMethod()) + "cannot have non runtime call: " + call.target;
+            HotSpotRuntimeCallTarget callTarget = (HotSpotRuntimeCallTarget) call.target;
+            assert callTarget.getAddress() == graalRuntime().getConfig().uncommonTrapStub || callTarget.isCRuntimeCall() : format("%h.%n(%p): ", getMethod()) +
+                            "must only call C runtime or deoptimization stub, not " + call.target;
         }
         return true;
     }
@@ -181,7 +196,7 @@
                     final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan,
                                     OptimisticOptimizations.ALL, new SpeculationLog());
 
-                    assert checkCompilationResult(compResult);
+                    assert checkStubInvariants(compResult);
 
                     assert definedRegisters != null;
                     code = Debug.scope("CodeInstall", new Callable<InstalledCode>() {
@@ -238,27 +253,29 @@
         }
     }
 
-    public static final Descriptor STUB_PRINTF = new Descriptor("stubPrintf", false, void.class, Word.class, long.class, long.class, long.class);
+    public static final Descriptor STUB_PRINTF_C = descriptorFor(Stub.class, "printfC", false);
 
-    @NodeIntrinsic(RuntimeCallNode.class)
-    private static native void printf(@ConstantNodeParameter Descriptor stubPrintf, Word format, long v1, long v2, long v3);
+    @NodeIntrinsic(CRuntimeCall.class)
+    private static native void printfC(@ConstantNodeParameter Descriptor stubPrintf, Word format, long v1, long v2, long v3);
 
     /**
-     * Prints a formatted string to the log stream.
+     * Prints a formatted string to the log stream. This differs from {@link Log#LOG_PRINTF} in that
+     * the format string is a C string in the C heap which avoids having an embedded oop in a
+     * RuntimeStub.
      * 
      * @param format a C style printf format value that can contain at most one conversion specifier
      *            (i.e., a sequence of characters starting with '%').
      * @param value the value associated with the conversion specifier
      */
     public static void printf(String format, long value) {
-        printf(STUB_PRINTF, cstring(format), value, 0L, 0L);
+        printfC(STUB_PRINTF_C, cstring(format), value, 0L, 0L);
     }
 
     public static void printf(String format, long v1, long v2) {
-        printf(STUB_PRINTF, cstring(format), v1, v2, 0L);
+        printfC(STUB_PRINTF_C, cstring(format), v1, v2, 0L);
     }
 
     public static void printf(String format, long v1, long v2, long v3) {
-        printf(STUB_PRINTF, cstring(format), v1, v2, v3);
+        printfC(STUB_PRINTF_C, cstring(format), v1, v2, v3);
     }
 }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Tue Apr 30 23:24:25 2013 +0200
@@ -51,7 +51,7 @@
         }
 
         @Override
-        public boolean hasCall() {
+        public boolean destroysCallerSavedRegisters() {
             return true;
         }
     }
@@ -112,8 +112,8 @@
         }
 
         @Override
-        public boolean hasCall() {
-            return !callTarget.preservesRegisters();
+        public boolean destroysCallerSavedRegisters() {
+            return callTarget.destroysRegisters();
         }
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Tue Apr 30 23:24:25 2013 +0200
@@ -244,7 +244,7 @@
     }
 
     public final boolean hasOperands() {
-        return instructionClass.hasOperands() || hasState() || hasCall();
+        return instructionClass.hasOperands() || hasState() || destroysCallerSavedRegisters();
     }
 
     public final boolean hasState() {
@@ -252,10 +252,9 @@
     }
 
     /**
-     * Returns true when this instruction is a call instruction that destroys all caller-saved
-     * registers.
+     * Determines if this instruction destroys all caller-saved registers..
      */
-    public boolean hasCall() {
+    public boolean destroysCallerSavedRegisters() {
         return false;
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Tue Apr 30 23:09:37 2013 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Tue Apr 30 23:24:25 2013 +0200
@@ -138,7 +138,7 @@
                 curInstruction = op;
 
                 op.forEachInput(useProc);
-                if (op.hasCall()) {
+                if (op.destroysCallerSavedRegisters()) {
                     for (Register register : frameMap.registerConfig.getCallerSaveRegisters()) {
                         curRegistersLive[register.number] = null;
                     }
--- a/src/cpu/x86/vm/graalRuntime_x86.cpp	Tue Apr 30 23:09:37 2013 +0200
+++ b/src/cpu/x86/vm/graalRuntime_x86.cpp	Tue Apr 30 23:24:25 2013 +0200
@@ -889,18 +889,6 @@
       break;
     }
 
-    case stub_printf_id: {
-      __ enter();
-      oop_maps = new OopMapSet();
-      OopMap* oop_map = save_live_registers(sasm, 4);
-      int call_offset = __ call_RT(noreg, noreg, (address)stub_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
-      oop_maps->add_gc_map(call_offset, oop_map);
-      restore_live_registers(sasm);
-      __ leave();
-      __ ret(0);
-      break;
-    }
-
     case log_primitive_id: {
       __ enter();
       oop_maps = new OopMapSet();
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Tue Apr 30 23:09:37 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue Apr 30 23:24:25 2013 +0200
@@ -761,7 +761,6 @@
   set_address("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id));
   set_address("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id));
   set_address("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id));
-  set_address("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap());
   set_address("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id));
   set_address("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id));
   set_address("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id));
@@ -776,7 +775,6 @@
   set_address("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id));
   set_address("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id));
   set_address("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id));
-  set_address("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id));
   set_address("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock());
   set_address("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock());
   set_address("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt());
@@ -787,6 +785,8 @@
   set_address("newMultiArrayAddress", GraalRuntime::new_multi_array);
   set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
   set_address("threadIsInterruptedAddress", GraalRuntime::thread_is_interrupted);
+  set_address("uncommonTrapStub", SharedRuntime::deopt_blob()->uncommon_trap());
+  set_address("stubPrintfAddress", GraalRuntime::stub_printf);
   set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code);
 
   set_int("deoptReasonNone", Deoptimization::Reason_none);
--- a/src/share/vm/graal/graalRuntime.cpp	Tue Apr 30 23:09:37 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Tue Apr 30 23:24:25 2013 +0200
@@ -570,7 +570,7 @@
   tty->print(buf, v1, v2, v3);
 JRT_END
 
-JRT_LEAF(void, GraalRuntime::stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3))
+JRT_LEAF(void, GraalRuntime::stub_printf(jlong format, jlong v1, jlong v2, jlong v3))
   ResourceMark rm;
   char *buf = (char*) (address) format;
   tty->print(buf, v1, v2, v3);
--- a/src/share/vm/graal/graalRuntime.hpp	Tue Apr 30 23:09:37 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Tue Apr 30 23:24:25 2013 +0200
@@ -94,7 +94,6 @@
   stub(create_out_of_bounds_exception) \
   stub(log_object)              \
   stub(log_printf)              \
-  stub(stub_printf)             \
   stub(log_primitive)           \
   stub(wb_pre_call)             \
   stub(wb_post_call)             \
@@ -137,7 +136,6 @@
   static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock);
   static void vm_error(JavaThread* thread, oop where, oop format, jlong value);
   static void log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3);
-  static void stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3);
   static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline);
   static void wb_pre_call(JavaThread* thread, oopDesc* obj);
   static void wb_post_call(JavaThread* thread, oopDesc* obj, void* card);
@@ -156,6 +154,7 @@
   static void new_array(JavaThread* thread, Klass* klass, jint length);
   static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims);
   static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte);
+  static void stub_printf(jlong format, jlong v1, jlong v2, jlong v3);
   static jint identity_hash_code(JavaThread* thread, oopDesc* objd);
   // initialization
   static void initialize(BufferBlob* blob);