diff c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotXirGenerator.java @ 1429:abc670a709dc

* -XX:TraceC1X=0...5 controls the native c1x tracing * -Dc1x.debug=true turns on the logging proxies and lots of log output on the java side * provide more information about types to the compiler (type hierarchy, etc) * provide exception handler tables to the compiler * add exception handlers to the nmethod * correct implementation of ExceptionObject * exception handling/unwinding entry points * modified versions of handle/unwind exception stubs using standard calling conventions * exception throwing * implicit null pointer exception, implicit div by 0 exception * arraystore/classcast/arrayindex exceptions * checkcast implementation * newarray, anewarray, multinewarray implementation * correct new instance initialization * access to java class mirrors (for ldc) * unresolved methods * class resolving - class patching (asssembly prototype copying)
author Lukas Stadler <lukas.stadler@oracle.com>
date Tue, 31 Aug 2010 22:13:30 -0700
parents 695451afc619
children 949ade3f2ff3
line wrap: on
line diff
--- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotXirGenerator.java	Thu Aug 19 14:34:52 2010 -0700
+++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotXirGenerator.java	Tue Aug 31 22:13:30 2010 -0700
@@ -19,6 +19,7 @@
 
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.concurrent.*;
 
 import com.sun.c1x.target.amd64.*;
 import com.sun.cri.ci.CiAddress.Scale;
@@ -36,16 +37,26 @@
 public class HotSpotXirGenerator implements RiXirGenerator {
 
     // this needs to correspond to c1x_CodeInstaller.hpp
-    private static final Integer MARK_VERIFIED_ENTRY = 0x0001;
-    private static final Integer MARK_UNVERIFIED_ENTRY = 0x0002;
-    private static final Integer MARK_OSR_ENTRY = 0x0003;
-    private static final Integer MARK_STATIC_CALL_STUB = 0x1000;
-    private static final Integer MARK_INVOKE_INVALID = 0x2000;
-    private static final Integer MARK_INVOKEINTERFACE = 0x2001;
-    private static final Integer MARK_INVOKESTATIC = 0x2002;
-    private static final Integer MARK_INVOKESPECIAL = 0x2003;
-    private static final Integer MARK_INVOKEVIRTUAL = 0x2004;
-    private static final Integer MARK_IMPLICIT_NULL_EXCEPTION_TARGET = 0x3000;
+    // @formatter:off
+    private static final Integer MARK_VERIFIED_ENTRY            = 0x0001;
+    private static final Integer MARK_UNVERIFIED_ENTRY          = 0x0002;
+    private static final Integer MARK_OSR_ENTRY                 = 0x0003;
+    private static final Integer MARK_UNWIND_ENTRY              = 0x0004;
+    private static final Integer MARK_EXCEPTION_HANDLER_ENTRY   = 0x0005;
+
+    private static final Integer MARK_STATIC_CALL_STUB          = 0x1000;
+
+    private static final Integer MARK_INVOKE_INVALID            = 0x2000;
+    private static final Integer MARK_INVOKEINTERFACE           = 0x2001;
+    private static final Integer MARK_INVOKESTATIC              = 0x2002;
+    private static final Integer MARK_INVOKESPECIAL             = 0x2003;
+    private static final Integer MARK_INVOKEVIRTUAL             = 0x2004;
+
+    private static final Integer MARK_IMPLICIT_NULL             = 0x3000;
+
+    private static final Integer MARK_KLASS_PATCHING            = 0x4000;
+    private static final Integer MARK_DUMMY_OOP_RELOCATION      = 0x4001;
+    // @formatter:on
 
     private final HotSpotVMConfig config;
     private final CiTarget target;
@@ -56,16 +67,24 @@
     private XirTemplate[] emptyTemplates = new XirTemplate[CiKind.values().length];
     private XirTemplate[] arrayLoadTemplates = new XirTemplate[CiKind.values().length];
     private XirTemplate[] arrayStoreTemplates = new XirTemplate[CiKind.values().length];
+    private XirTemplate[] arrayLoadTemplatesWithLength = new XirTemplate[CiKind.values().length];
+    private XirTemplate[] arrayStoreTemplatesWithLength = new XirTemplate[CiKind.values().length];
     private XirTemplate prologueTemplate;
     private XirTemplate staticPrologueTemplate;
     private XirTemplate epilogueTemplate;
     private XirTemplate arrayLengthTemplate;
+    private XirTemplate safepointTemplate;
     private XirTemplate exceptionObjectTemplate;
     private XirTemplate invokeStaticTemplate;
     private XirTemplate invokeSpecialTemplate;
     private XirTemplate invokeInterfaceTemplate;
     private XirTemplate invokeVirtualTemplate;
-    private XirTemplate newInstanceTemplate;
+
+    private XirTemplate newInstanceUnresolvedTemplate;
+    private XirPair newObjectArrayTemplate;
+    private XirTemplate newTypeArrayTemplate;
+    private XirPair resolveClassTemplate;
+    private XirPair checkCastTemplate;
 
     static class XirPair {
 
@@ -80,8 +99,8 @@
 
     private XirPair[] putFieldTemplates = new XirPair[CiKind.values().length];
     private XirPair[] getFieldTemplates = new XirPair[CiKind.values().length];
-    private XirPair[] putStaticFieldTemplates = new XirPair[CiKind.values().length];
-    private XirPair[] getStaticFieldTemplates = new XirPair[CiKind.values().length];
+    private XirPair[] putStaticTemplates = new XirPair[CiKind.values().length];
+    private XirPair[] getStaticTemplates = new XirPair[CiKind.values().length];
     private XirPair instanceofTemplate;
     private XirPair instanceofTemplateNonnull;
 
@@ -107,12 +126,14 @@
                 XirOperand result = asm.createTemp("result", kind);
                 emptyTemplates[index] = asm.finishTemplate(result, "empty-" + kind);
 
-                putFieldTemplates[index] = buildPutFieldTemplate(kind, kind == CiKind.Object, false);
-                getFieldTemplates[index] = buildGetFieldTemplate(kind, false);
-                putStaticFieldTemplates[index] = buildPutFieldTemplate(kind, kind == CiKind.Object, true);
-                getStaticFieldTemplates[index] = buildGetFieldTemplate(kind, true);
-                arrayLoadTemplates[index] = buildArrayLoad(kind, asm, true);
-                arrayStoreTemplates[index] = buildArrayStore(kind, asm, true, kind == CiKind.Object, kind == CiKind.Object);
+                putFieldTemplates[index] = buildPutFieldTemplate(kind, kind == CiKind.Object);
+                getFieldTemplates[index] = buildGetFieldTemplate(kind);
+                putStaticTemplates[index] = buildPutStaticTemplate(kind, kind == CiKind.Object);
+                getStaticTemplates[index] = buildGetStaticTemplate(kind);
+                arrayLoadTemplates[index] = buildArrayLoad(kind, asm, true, false);
+                arrayStoreTemplates[index] = buildArrayStore(kind, asm, true, kind == CiKind.Object, kind == CiKind.Object, false);
+                arrayLoadTemplatesWithLength[index] = buildArrayLoad(kind, asm, true, true);
+                arrayStoreTemplatesWithLength[index] = buildArrayStore(kind, asm, true, kind == CiKind.Object, kind == CiKind.Object, true);
                 // newArrayTemplates[index] = buildNewArray(kind);
             }
             // templates.add(emptyTemplates[index]);
@@ -127,21 +148,43 @@
         epilogueTemplate = buildEpilogue();
         arrayLengthTemplate = buildArrayLength();
         exceptionObjectTemplate = buildExceptionObject();
+        safepointTemplate = buildSafepoint();
         instanceofTemplate = buildInstanceof(false);
         instanceofTemplateNonnull = buildInstanceof(true);
         invokeStaticTemplate = buildInvokeStatic();
         invokeSpecialTemplate = buildInvokeSpecial();
         invokeInterfaceTemplate = buildInvokeInterface();
         invokeVirtualTemplate = buildInvokeVirtual();
-        newInstanceTemplate = buildNewInstance();
+        newInstanceUnresolvedTemplate = buildNewInstanceUnresolved();
+        newObjectArrayTemplate = new XirPair(buildNewObjectArray(true), buildNewObjectArray(false));
+        newTypeArrayTemplate = buildNewTypeArray();
+        resolveClassTemplate = new XirPair(buildResolveClass(true), buildResolveClass(false));
+        checkCastTemplate = buildCheckCast();
 
         return templates;
     }
 
+    private final OndemandTemplates<XirTemplate> newInstanceTemplates = new OndemandTemplates<XirTemplate>() {
+
+        @Override
+        protected XirTemplate create(CiXirAssembler asm, int size) {
+            return buildNewInstance(asm, size);
+        }
+    };
+
+    private final OndemandTemplates<XirPair> multiNewArrayTemplate = new OndemandTemplates<HotSpotXirGenerator.XirPair>() {
+
+        @Override
+        protected XirPair create(CiXirAssembler asm, int dimensions) {
+            return new XirPair(buildMultiNewArray(dimensions, true), buildMultiNewArray(dimensions, false));
+        }
+    };
+
     private XirTemplate buildPrologue(boolean staticMethod) {
         asm.restart(CiKind.Void);
         XirOperand temp = asm.createRegister("temp (rax)", CiKind.Int, AMD64.rax);
-        XirOperand frame_pointer = asm.createRegister("frame pointer", CiKind.Word, AMD64.rbp);
+        XirOperand framePointer = asm.createRegister("frame pointer", CiKind.Word, AMD64.rbp);
+        XirOperand stackPointer = asm.createRegister("stack pointer", CiKind.Word, AMD64.rsp);
 
         asm.align(config.codeEntryAlignment);
         asm.mark(MARK_OSR_ENTRY);
@@ -155,35 +198,75 @@
             asm.align(config.codeEntryAlignment);
         }
         asm.mark(MARK_VERIFIED_ENTRY);
-        asm.push(frame_pointer);
+        asm.push(framePointer);
+        asm.mov(framePointer, stackPointer);
         asm.pushFrame();
 
+        // -- out of line -------------------------------------------------------
+        XirOperand thread = asm.createRegister("thread", CiKind.Word, AMD64.r15);
+        XirOperand exceptionOop = asm.createTemp("exception oop", CiKind.Object);
+        XirLabel unwind = asm.createOutOfLineLabel("unwind");
+        asm.bindOutOfLine(unwind);
+
+        asm.mark(MARK_UNWIND_ENTRY);
+        //asm.popFrame();
+        //asm.pop(framePointer);
+
+        // TODO synchronized methods / monitors
+
+        asm.pload(CiKind.Object, exceptionOop, thread, asm.i(config.threadExceptionOopOffset), false);
+        asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.createConstant(CiConstant.NULL_OBJECT), false);
+        asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false);
+
+        asm.callRuntime(config.unwindExceptionStub, null, exceptionOop);
+        asm.shouldNotReachHere();
+
+        asm.mark(MARK_EXCEPTION_HANDLER_ENTRY);
+        asm.callRuntime(config.handleExceptionStub, null);
+        asm.shouldNotReachHere();
+
         return asm.finishTemplate(staticMethod ? "static prologue" : "prologue");
     }
 
     private XirTemplate buildEpilogue() {
         asm.restart(CiKind.Void);
-        XirOperand frame_pointer = asm.createRegister("frame pointer", CiKind.Word, AMD64.rbp);
+        XirOperand framePointer = asm.createRegister("frame pointer", CiKind.Word, AMD64.rbp);
+
         asm.popFrame();
-        asm.pop(frame_pointer);
+        asm.pop(framePointer);
         // TODO safepoint check
+
         return asm.finishTemplate("epilogue");
     }
 
     private XirTemplate buildArrayLength() {
         XirOperand result = asm.restart(CiKind.Int);
         XirParameter object = asm.createInputParameter("object", CiKind.Object);
+        asm.mark(MARK_IMPLICIT_NULL);
         asm.pload(CiKind.Int, result, object, asm.i(config.arrayLengthOffset), true);
         return asm.finishTemplate("arrayLength");
     }
 
     private XirTemplate buildExceptionObject() {
-        asm.restart();
-        XirOperand temp = asm.createRegister("temp (rax)", CiKind.Object, AMD64.rax);
-        return asm.finishTemplate(temp, "exception object");
+        XirOperand result = asm.restart(CiKind.Object);
+        XirOperand thread = asm.createRegister("thread", CiKind.Word, AMD64.r15);
+
+        asm.pload(CiKind.Object, result, thread, asm.i(config.threadExceptionOopOffset), false);
+        asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.o(null), false);
+        asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false);
+
+        return asm.finishTemplate("exception object");
     }
 
-    private XirPair buildGetFieldTemplate(CiKind kind, boolean isStatic) {
+    private XirTemplate buildSafepoint() {
+        asm.restart(CiKind.Void);
+
+        // TODO safepoint
+
+        return asm.finishTemplate("safepoint");
+    }
+
+    private XirPair buildGetFieldTemplate(CiKind kind) {
         final XirTemplate resolved;
         final XirTemplate unresolved;
         {
@@ -191,31 +274,52 @@
             XirOperand result = asm.restart(kind);
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
             XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int);
+            asm.mark(MARK_IMPLICIT_NULL);
             asm.pload(kind, result, object, fieldOffset, true);
             resolved = asm.finishTemplate("getfield<" + kind + ">");
         }
-        if (isStatic) {
-            asm.restart(kind);
-            asm.shouldNotReachHere();
-
-// XirParameter object = asm.createInputParameter("object", CiKind.Object);
-// XirParameter guard = asm.createInputParameter("guard", CiKind.Object);
-// XirOperand fieldOffset = asm.createTemp("fieldOffset", CiKind.Int);
-// if (isStatic) {
-// callRuntimeThroughStub(asm, "resolveGetStatic", fieldOffset, guard);
-// } else {
-// callRuntimeThroughStub(asm, "resolveGetField", fieldOffset, guard);
-// }
-// asm.pload(kind, result, object, fieldOffset, true);
-
-            unresolved = asm.finishTemplate("getfield<" + kind + ">-unresolved");
-        } else {
-            unresolved = null;
-        }
+        unresolved = null;
         return new XirPair(resolved, unresolved);
     }
 
-    private XirPair buildPutFieldTemplate(CiKind kind, boolean genWriteBarrier, boolean isStatic) {
+    private XirPair buildPutFieldTemplate(CiKind kind, boolean genWriteBarrier) {
+        final XirTemplate resolved;
+        final XirTemplate unresolved;
+        {
+            // resolved case
+            asm.restart(CiKind.Void);
+            XirParameter object = asm.createInputParameter("object", CiKind.Object);
+            XirParameter value = asm.createInputParameter("value", kind);
+            XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int);
+            asm.mark(MARK_IMPLICIT_NULL);
+            asm.pstore(kind, object, fieldOffset, value, true);
+            if (genWriteBarrier) {
+                // TODO write barrier
+                // addWriteBarrier(asm, object, value);
+            }
+            resolved = asm.finishTemplate("putfield<" + kind + ", " + genWriteBarrier + ">");
+        }
+        unresolved = null;
+        return new XirPair(resolved, unresolved);
+    }
+
+    private XirPair buildGetStaticTemplate(CiKind kind) {
+        final XirTemplate resolved;
+        final XirTemplate unresolved;
+        {
+            // resolved case
+            XirOperand result = asm.restart(kind);
+            XirParameter object = asm.createInputParameter("object", CiKind.Object);
+            XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int);
+            asm.mark(MARK_IMPLICIT_NULL);
+            asm.pload(kind, result, object, fieldOffset, true);
+            resolved = asm.finishTemplate("getfield<" + kind + ">");
+        }
+        unresolved = null;
+        return new XirPair(resolved, unresolved);
+    }
+
+    private XirPair buildPutStaticTemplate(CiKind kind, boolean genWriteBarrier) {
         final XirTemplate resolved;
         final XirTemplate unresolved;
         {
@@ -224,6 +328,7 @@
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
             XirParameter value = asm.createInputParameter("value", kind);
             XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int);
+            asm.mark(MARK_IMPLICIT_NULL);
             asm.pstore(kind, object, fieldOffset, value, true);
             if (genWriteBarrier) {
                 // TODO write barrier
@@ -231,147 +336,251 @@
             }
             resolved = asm.finishTemplate("putfield<" + kind + ", " + genWriteBarrier + ">");
         }
-        if (isStatic) {
-            // unresolved case
-            asm.restart(CiKind.Void);
-            asm.shouldNotReachHere();
-
-//            XirParameter object = asm.createInputParameter("object", CiKind.Object);
-//            XirParameter value = asm.createInputParameter("value", kind);
-//            XirParameter guard = asm.createInputParameter("guard", CiKind.Object);
-//            XirOperand fieldOffset = asm.createTemp("fieldOffset", CiKind.Int);
-//            if (isStatic) {
-//                callRuntimeThroughStub(asm, "resolvePutStatic", fieldOffset, guard);
-//            } else {
-//                callRuntimeThroughStub(asm, "resolvePutField", fieldOffset, guard);
-//            }
-//            asm.pstore(kind, object, fieldOffset, value, true);
-//            if (genWriteBarrier) {
-//                addWriteBarrier(asm, object, value);
-//            }
-
-            unresolved = asm.finishTemplate("putfield<" + kind + ", " + genWriteBarrier + ">-unresolved");
-        } else {
-            unresolved = null;
-        }
+        unresolved = null;
         return new XirPair(resolved, unresolved);
     }
 
     private XirPair buildInstanceof(boolean nonnull) {
-        XirTemplate resolved;
-        XirTemplate unresolved;
+        final XirTemplate resolved;
+        final XirTemplate unresolved;
         {
             XirOperand result = asm.restart(CiKind.Boolean);
 
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
             XirParameter hub = asm.createConstantInputParameter("hub", CiKind.Object);
-            XirOperand temp = asm.createTemp("temp", CiKind.Object);
+            XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
+
             XirLabel end = asm.createInlineLabel("end");
             XirLabel slow_path = asm.createOutOfLineLabel("slow path");
 
-            asm.mov(result, asm.b(false));
             if (!nonnull) {
-                // first check for null
+                // null isn't "instanceof" anything
+                asm.mov(result, asm.b(false));
                 asm.jeq(end, object, asm.o(null));
             }
-            asm.pload(CiKind.Object, temp, object, asm.i(config.hubOffset), !nonnull);
+            asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
+            // if we get an exact match: succeed immediately
             asm.mov(result, asm.b(true));
-            asm.jneq(slow_path, temp, hub);
-
+            asm.jneq(slow_path, objHub, hub);
             asm.bindInline(end);
 
+            // -- out of line -------------------------------------------------------
             asm.bindOutOfLine(slow_path);
-            asm.push(temp);
-            asm.push(hub);
-            asm.callRuntime(config.instanceofStub, result);
-            asm.pop(hub);
-            asm.pop(result);
+            checkSubtype(result, objHub, hub);
             asm.jmp(end);
+
             resolved = asm.finishTemplate("instanceof-leaf<" + nonnull + ">");
         }
-        {/*
-          * // unresolved instanceof unresolved = buildUnresolvedInstanceOf(nonnull);
-          */
-            asm.restart(CiKind.Boolean);
+        {
+            XirOperand result = asm.restart(CiKind.Boolean);
+
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
-            System.out.println(object);
-            asm.shouldNotReachHere();
+            XirOperand hub = asm.createTemp("hub", CiKind.Object);
+            XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
+
+            XirLabel end = asm.createInlineLabel("end");
+            XirLabel slow_path = asm.createOutOfLineLabel("slow path");
+
+            // insert the patching code for class resolving - the hub will end up in "hub"
+            UnresolvedClassPatching patching = new UnresolvedClassPatching(asm, hub, config);
+            patching.emitInline();
+
+            if (!nonnull) {
+                // null isn't "instanceof" anything
+                asm.mov(result, asm.b(false));
+                asm.jeq(end, object, asm.o(null));
+            }
+            asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
+            // if we get an exact match: succeed immediately
+            asm.mov(result, asm.b(true));
+            asm.jneq(slow_path, objHub, hub);
+            asm.bindInline(end);
+
+            // -- out of line -------------------------------------------------------
+            asm.bindOutOfLine(slow_path);
+            checkSubtype(result, objHub, hub);
+            asm.jmp(end);
+
+            patching.emitOutOfLine();
+
             unresolved = asm.finishTemplate("instanceof-leaf<" + nonnull + ">");
         }
         return new XirPair(resolved, unresolved);
     }
 
-    private XirTemplate buildArrayStore(CiKind kind, CiXirAssembler asm, boolean genBoundsCheck, boolean genStoreCheck, boolean genWriteBarrier) {
+    private XirPair buildCheckCast() {
+        final XirTemplate resolved;
+        final XirTemplate unresolved;
+        {
+            asm.restart();
+
+            XirParameter object = asm.createInputParameter("object", CiKind.Object);
+            XirParameter hub = asm.createConstantInputParameter("hub", CiKind.Object);
+            XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
+
+            XirLabel end = asm.createInlineLabel("end");
+            XirLabel slow_path = asm.createOutOfLineLabel("slow path");
+
+            // null can be cast to anything
+            asm.jeq(end, object, asm.o(null));
+
+            asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
+            // if we get an exact match: succeed immediately
+            asm.jneq(slow_path, objHub, hub);
+            asm.bindInline(end);
+
+            // -- out of line -------------------------------------------------------
+            asm.bindOutOfLine(slow_path);
+            checkSubtype(objHub, objHub, hub);
+            asm.jneq(end, objHub, asm.o(null));
+            XirOperand scratch = asm.createRegister("scratch", CiKind.Object, AMD64.r10);
+            asm.mov(scratch, object);
+            asm.callRuntime(config.throwClassCastException, null);
+            asm.shouldNotReachHere();
+
+            resolved = asm.finishTemplate(object, "check cast");
+        }
+        {
+            asm.restart();
+
+            XirParameter object = asm.createInputParameter("object", CiKind.Object);
+            XirOperand hub = asm.createTemp("hub", CiKind.Object);
+            XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
+
+            XirLabel end = asm.createInlineLabel("end");
+            XirLabel slow_path = asm.createOutOfLineLabel("slow path");
+
+            // insert the patching code for class resolving - the hub will end up in "hub"
+            UnresolvedClassPatching patching = new UnresolvedClassPatching(asm, hub, config);
+            patching.emitInline();
+
+            // null can be cast to anything
+            asm.jeq(end, object, asm.o(null));
+
+            asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
+            // if we get an exact match: succeed immediately
+            asm.jneq(slow_path, objHub, hub);
+            asm.bindInline(end);
+
+            // -- out of line -------------------------------------------------------
+            asm.bindOutOfLine(slow_path);
+            checkSubtype(objHub, objHub, hub);
+            asm.jneq(end, objHub, asm.o(null));
+            XirOperand scratch = asm.createRegister("scratch", CiKind.Object, AMD64.r10);
+            asm.mov(scratch, object);
+            asm.callRuntime(config.throwClassCastException, null);
+            asm.shouldNotReachHere();
+
+            patching.emitOutOfLine();
+
+            unresolved = asm.finishTemplate(object, "check cast");
+        }
+        return new XirPair(resolved, unresolved);
+    }
+
+    private XirTemplate buildArrayStore(CiKind kind, CiXirAssembler asm, boolean genBoundsCheck, boolean genStoreCheck, boolean genWriteBarrier, boolean withLength) {
         asm.restart(CiKind.Void);
         XirParameter array = asm.createInputParameter("array", CiKind.Object);
         XirParameter index = asm.createInputParameter("index", CiKind.Int);
         XirParameter value = asm.createInputParameter("value", kind);
-        XirOperand length = asm.createTemp("length", CiKind.Int);
         XirOperand temp = asm.createTemp("temp", CiKind.Word);
         XirOperand valueHub = null;
         XirOperand compHub = null;
         XirLabel store = asm.createInlineLabel("store");
         XirLabel failBoundsCheck = null;
         XirLabel slowStoreCheck = null;
+        // if the length is known the array cannot be null
+        boolean implicitNullException = !withLength;
+
         if (genBoundsCheck) {
             // load the array length and check the index
             failBoundsCheck = asm.createOutOfLineLabel("failBoundsCheck");
-            asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), true);
+            XirOperand length;
+            if (withLength) {
+                length = asm.createInputParameter("length", CiKind.Int);
+            } else {
+                length = asm.createTemp("length", CiKind.Int);
+                asm.mark(MARK_IMPLICIT_NULL);
+                asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), true);
+                implicitNullException = false;
+            }
             asm.jugteq(failBoundsCheck, index, length);
+
         }
         if (genStoreCheck) {
             slowStoreCheck = asm.createOutOfLineLabel("slowStoreCheck");
             asm.jeq(store, value, asm.o(null)); // first check if value is null
             valueHub = asm.createTemp("valueHub", CiKind.Object);
             compHub = asm.createTemp("compHub", CiKind.Object);
-            asm.pload(CiKind.Object, compHub, array, asm.i(config.hubOffset), !genBoundsCheck);
+            if (implicitNullException) {
+                asm.mark(MARK_IMPLICIT_NULL);
+            }
+            asm.pload(CiKind.Object, compHub, array, asm.i(config.hubOffset), implicitNullException);
             asm.pload(CiKind.Object, compHub, compHub, asm.i(config.arrayClassElementOffset), false);
             asm.pload(CiKind.Object, valueHub, value, asm.i(config.hubOffset), false);
             asm.jneq(slowStoreCheck, compHub, valueHub); // then check component hub matches value hub
+
+            implicitNullException = false;
         }
         asm.bindInline(store);
         int elemSize = target.sizeInBytes(kind);
-        asm.pstore(kind, array, index, value, config.getArrayOffset(kind), Scale.fromInt(elemSize), !genBoundsCheck && !genStoreCheck);
+
+        if (implicitNullException) {
+            asm.mark(MARK_IMPLICIT_NULL);
+        }
+        asm.pstore(kind, array, index, value, config.getArrayOffset(kind), Scale.fromInt(elemSize), implicitNullException);
         if (genWriteBarrier) {
             // addWriteBarrier(asm, array, value);
         }
+
+        // -- out of line -------------------------------------------------------
         if (genBoundsCheck) {
             asm.bindOutOfLine(failBoundsCheck);
+            asm.callRuntime(config.throwArrayIndexException, null);
             asm.shouldNotReachHere();
-            // callRuntimeThroughStub(asm, "throwArrayIndexOutOfBoundsException", null, array, index);
         }
         if (genStoreCheck) {
             asm.bindOutOfLine(slowStoreCheck);
-            asm.push(valueHub);
-            asm.push(compHub);
-            asm.callRuntime(config.instanceofStub, null);
-            asm.pop(temp);
-            asm.pop(temp);
+            checkSubtype(temp, valueHub, compHub);
             asm.jneq(store, temp, asm.w(0));
-            asm.shouldNotReachHere();
+            asm.callRuntime(config.throwArrayStoreException, null);
             asm.jmp(store);
         }
         return asm.finishTemplate("arraystore<" + kind + ">");
     }
 
-    private XirTemplate buildArrayLoad(CiKind kind, CiXirAssembler asm, boolean genBoundsCheck) {
+    private XirTemplate buildArrayLoad(CiKind kind, CiXirAssembler asm, boolean genBoundsCheck, boolean withLength) {
         XirOperand result = asm.restart(kind);
         XirParameter array = asm.createInputParameter("array", CiKind.Object);
         XirParameter index = asm.createInputParameter("index", CiKind.Int);
-        XirOperand length = asm.createTemp("length", CiKind.Int);
-        XirLabel fail = null;
+        XirLabel failBoundsCheck = null;
+        // if the length is known the array cannot be null
+        boolean implicitNullException = !withLength;
+
         if (genBoundsCheck) {
             // load the array length and check the index
-            fail = asm.createOutOfLineLabel("fail");
-            asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), true);
-            asm.jugteq(fail, index, length);
+            failBoundsCheck = asm.createOutOfLineLabel("failBoundsCheck");
+            XirOperand length;
+            if (withLength) {
+                length = asm.createInputParameter("length", CiKind.Int);
+            } else {
+                length = asm.createTemp("length", CiKind.Int);
+                asm.mark(MARK_IMPLICIT_NULL);
+                asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), true);
+                implicitNullException = false;
+            }
+            asm.jugteq(failBoundsCheck, index, length);
+            implicitNullException = false;
         }
         int elemSize = target.sizeInBytes(kind);
-        asm.pload(kind, result, array, index, config.getArrayOffset(kind), Scale.fromInt(elemSize), !genBoundsCheck);
+        if (implicitNullException) {
+            asm.mark(MARK_IMPLICIT_NULL);
+        }
+        asm.pload(kind, result, array, index, config.getArrayOffset(kind), Scale.fromInt(elemSize), implicitNullException);
         if (genBoundsCheck) {
-            asm.bindOutOfLine(fail);
+            asm.bindOutOfLine(failBoundsCheck);
+            asm.callRuntime(config.throwArrayIndexException, null);
             asm.shouldNotReachHere();
-            // callRuntimeThroughStub(asm, "throwArrayIndexOutOfBoundsException", null, array, index);
         }
         return asm.finishTemplate("arrayload<" + kind + ">");
     }
@@ -383,6 +592,7 @@
         XirLabel stub = asm.createOutOfLineLabel("call stub");
         asm.mark(MARK_INVOKESTATIC);
 
+        // -- out of line -------------------------------------------------------
         asm.bindOutOfLine(stub);
         XirOperand method = asm.createRegister("method", CiKind.Word, AMD64.rbx);
         asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE);
@@ -396,11 +606,16 @@
 
     private XirTemplate buildInvokeSpecial() {
         asm.restart();
+        XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object);
         XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word);
+        XirOperand temp = asm.createRegister("temp", CiKind.Word, AMD64.rax);
+        XirLabel stub = asm.createOutOfLineLabel("call stub");
 
-        XirLabel stub = asm.createOutOfLineLabel("call stub");
+        asm.mark(MARK_IMPLICIT_NULL);
+        asm.pload(CiKind.Word, temp, receiver, true);
         asm.mark(MARK_INVOKESPECIAL);
 
+        // -- out of line -------------------------------------------------------
         asm.bindOutOfLine(stub);
         XirOperand method = asm.createRegister("method", CiKind.Word, AMD64.rbx);
         asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE);
@@ -414,13 +629,18 @@
 
     private XirTemplate buildInvokeInterface() {
         asm.restart();
+        XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object);
         XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word);
         XirOperand method = asm.createRegister("method", CiKind.Object, AMD64.rbx);
+        XirOperand temp = asm.createRegister("temp", CiKind.Word, AMD64.rax);
+        XirLabel stub = asm.createOutOfLineLabel("call stub");
 
-        XirLabel stub = asm.createOutOfLineLabel("call stub");
+        asm.mark(MARK_IMPLICIT_NULL);
+        asm.pload(CiKind.Word, temp, receiver, true);
         asm.mark(MARK_INVOKEINTERFACE);
         asm.mov(method, asm.createConstant(CiConstant.forObject(HotSpotProxy.DUMMY_CONSTANT_OBJ)));
 
+        // -- out of line -------------------------------------------------------
         asm.bindOutOfLine(stub);
         asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE);
         asm.mov(method, asm.w(0l));
@@ -433,13 +653,18 @@
 
     private XirTemplate buildInvokeVirtual() {
         asm.restart();
+        XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object);
         XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word);
         XirOperand method = asm.createRegister("method", CiKind.Object, AMD64.rbx);
+        XirOperand temp = asm.createRegister("temp", CiKind.Word, AMD64.rax);
+        XirLabel stub = asm.createOutOfLineLabel("call stub");
 
-        XirLabel stub = asm.createOutOfLineLabel("call stub");
+        asm.mark(MARK_IMPLICIT_NULL);
+        asm.pload(CiKind.Word, temp, receiver, true);
         asm.mark(MARK_INVOKEVIRTUAL);
         asm.mov(method, asm.createConstant(CiConstant.forObject(HotSpotProxy.DUMMY_CONSTANT_OBJ)));
 
+        // -- out of line -------------------------------------------------------
         asm.bindOutOfLine(stub);
         asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE);
         asm.mov(method, asm.w(0l));
@@ -447,25 +672,22 @@
         asm.jmp(dummy);
         asm.bindOutOfLine(dummy);
 
-        asm.mark(MARK_IMPLICIT_NULL_EXCEPTION_TARGET, XirMark.CALLSITE);
-        asm.callRuntime(config.throwImplicitNullStub, null);
-
         return asm.finishTemplate(addr, "invokespecial");
     }
 
-    private XirTemplate buildNewInstance() {
+    private XirTemplate buildNewInstance(CiXirAssembler asm, int size) {
         XirOperand result = asm.restart(CiKind.Word);
         XirOperand type = asm.createInputParameter("type", CiKind.Object);
-        XirOperand instanceSize = asm.createConstantInputParameter("instance size", CiKind.Word);
 
         XirOperand thread = asm.createRegister("thread", CiKind.Word, AMD64.r15);
-        XirOperand temp1 = asm.createTemp("temp1", CiKind.Word);
-        XirOperand temp2 = asm.createTemp("temp2", CiKind.Word);
+        XirOperand temp1 = asm.createRegister("temp1", CiKind.Word, AMD64.rcx);
+        XirOperand temp2 = asm.createRegister("temp2", CiKind.Word, AMD64.rbx);
+        useRegisters(asm, AMD64.rsi);
         XirLabel tlabFull = asm.createOutOfLineLabel("tlab full");
         XirLabel resume = asm.createInlineLabel("resume");
 
         asm.pload(CiKind.Word, result, thread, asm.i(config.threadTlabTopOffset), false);
-        asm.add(temp1, result, instanceSize);
+        asm.add(temp1, result, asm.w(size));
         asm.pload(CiKind.Word, temp2, thread, asm.i(config.threadTlabEndOffset), false);
 
         asm.jgt(tlabFull, temp1, temp2);
@@ -476,6 +698,14 @@
         asm.pstore(CiKind.Word, result, temp1, false);
         asm.pstore(CiKind.Object, result, asm.i(config.hubOffset), type, false);
 
+        if (size > 2 * target.wordSize) {
+            asm.mov(temp1, asm.w(0));
+            for (int offset = 2 * target.wordSize; offset < size; offset += target.wordSize) {
+                asm.pstore(CiKind.Word, result, asm.i(offset), temp1, false);
+            }
+        }
+
+        // -- out of line -------------------------------------------------------
         asm.bindOutOfLine(tlabFull);
         XirOperand arg = asm.createRegister("runtime call argument", CiKind.Object, AMD64.rdx);
         asm.mov(arg, type);
@@ -485,6 +715,110 @@
         return asm.finishTemplate("new instance");
     }
 
+    private XirTemplate buildNewInstanceUnresolved() {
+        XirOperand result = asm.restart(CiKind.Word);
+        XirOperand arg = asm.createRegister("runtime call argument", CiKind.Object, AMD64.rdx);
+
+        UnresolvedClassPatching patching = new UnresolvedClassPatching(asm, arg, config);
+
+        patching.emitInline();
+        useRegisters(AMD64.rbx, AMD64.rcx, AMD64.rsi);
+        asm.callRuntime(config.newInstanceStub, result);
+
+        // -- out of line -------------------------------------------------------
+        patching.emitOutOfLine();
+
+        return asm.finishTemplate("new instance");
+    }
+
+    private XirTemplate buildNewObjectArray(boolean resolved) {
+        XirOperand result = asm.restart(CiKind.Object);
+
+        XirParameter lengthParam = asm.createInputParameter("length", CiKind.Int);
+
+        XirOperand length = asm.createRegister("length", CiKind.Int, AMD64.rbx);
+        XirOperand hub = asm.createRegister("hub", CiKind.Object, AMD64.rdx);
+
+        UnresolvedClassPatching patching = null;
+        if (resolved) {
+            asm.mov(hub, asm.createConstantInputParameter("hub", CiKind.Object));
+        } else {
+            // insert the patching code for class resolving - the hub will end up in "hub"
+            patching = new UnresolvedClassPatching(asm, hub, config);
+            patching.emitInline();
+        }
+
+        asm.mov(length, lengthParam);
+        useRegisters(AMD64.rsi, AMD64.rcx, AMD64.rdi);
+        asm.callRuntime(config.newObjectArrayStub, result);
+        if (!resolved) {
+            patching.emitOutOfLine();
+        }
+        return asm.finishTemplate(resolved ? "newObjectArray" : "newObjectArray (unresolved)");
+    }
+
+    private XirTemplate buildMultiNewArray(int dimensions, boolean resolved) {
+        XirOperand result = asm.restart(CiKind.Object);
+
+        XirOperand hub = asm.createRegister("hub", CiKind.Object, AMD64.rax);
+        XirOperand rank = asm.createRegister("rank", CiKind.Int, AMD64.rbx);
+        XirOperand sizes = asm.createRegister("sizes", CiKind.Long, AMD64.rcx);
+        XirOperand thread = asm.createRegister("thread", CiKind.Long, AMD64.r15);
+        asm.add(sizes, thread, asm.l(config.threadMultiNewArrayStorage));
+        for (int i = 0; i < dimensions; i++) {
+            XirParameter length = asm.createInputParameter("length" + i, CiKind.Int);
+            asm.pstore(CiKind.Int, sizes, asm.i(i * target.sizeInBytes(CiKind.Int)), length, false);
+        }
+
+        UnresolvedClassPatching patching = null;
+        if (resolved) {
+            asm.mov(hub, asm.createConstantInputParameter("hub", CiKind.Object));
+        } else {
+            // insert the patching code for class resolving - the hub will end up in "hub"
+            patching = new UnresolvedClassPatching(asm, hub, config);
+            patching.emitInline();
+        }
+
+        asm.mov(rank, asm.i(dimensions));
+        asm.callRuntime(config.newMultiArrayStub, result);
+        if (!resolved) {
+            patching.emitOutOfLine();
+        }
+        return asm.finishTemplate(resolved ? "multiNewArray" + dimensions : "multiNewArray" + dimensions + " (unresolved)");
+    }
+
+    private XirTemplate buildNewTypeArray() {
+        XirOperand result = asm.restart(CiKind.Object);
+
+        XirParameter lengthParam = asm.createInputParameter("length", CiKind.Int);
+        XirParameter hubParam = asm.createConstantInputParameter("hub", CiKind.Object);
+
+        XirOperand length = asm.createRegister("length", CiKind.Int, AMD64.rbx);
+        XirOperand hub = asm.createRegister("hub", CiKind.Object, AMD64.rdx);
+
+        asm.mov(hub, hubParam);
+        asm.mov(length, lengthParam);
+        useRegisters(AMD64.rsi, AMD64.rcx, AMD64.rdi);
+        asm.callRuntime(config.newTypeArrayStub, result);
+
+        return asm.finishTemplate("newObjectArray");
+    }
+
+    private XirTemplate buildResolveClass(boolean resolved) {
+        XirOperand result = asm.restart(CiKind.Word);
+        if (resolved) {
+            XirOperand type = asm.createConstantInputParameter("type", CiKind.Object);
+
+            asm.mov(result, type);
+        } else {
+            UnresolvedClassPatching patching = new UnresolvedClassPatching(asm, result, config);
+            patching.emitInline();
+            // -- out of line -------------------------------------------------------
+            patching.emitOutOfLine();
+        }
+        return asm.finishTemplate(resolved ? "resolve class" : "resolve class (unresolved)");
+    }
+
     @Override
     public XirSnippet genArrayLength(XirSite site, XirArgument array) {
         return new XirSnippet(arrayLengthTemplate, array);
@@ -492,19 +826,26 @@
 
     @Override
     public XirSnippet genArrayLoad(XirSite site, XirArgument array, XirArgument index, XirArgument length, CiKind elementKind, RiType elementType) {
-        // TODO: emit different template if length is present
-        return new XirSnippet(arrayLoadTemplates[elementKind.ordinal()], array, index);
+        if (length == null) {
+            return new XirSnippet(arrayLoadTemplates[elementKind.ordinal()], array, index);
+        }
+        return new XirSnippet(arrayLoadTemplatesWithLength[elementKind.ordinal()], array, index, length);
     }
 
     @Override
     public XirSnippet genArrayStore(XirSite site, XirArgument array, XirArgument index, XirArgument length, XirArgument value, CiKind elementKind, RiType elementType) {
-        // TODO: emit different template if length is present
-        return new XirSnippet(arrayStoreTemplates[elementKind.ordinal()], array, index, value);
+        if (length == null) {
+            return new XirSnippet(arrayStoreTemplates[elementKind.ordinal()], array, index, value);
+        }
+        return new XirSnippet(arrayStoreTemplatesWithLength[elementKind.ordinal()], array, index, value, length);
     }
 
     @Override
     public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type) {
-        return new XirSnippet(emptyTemplates[CiKind.Object.ordinal()]);
+        if (type.isResolved()) {
+            return new XirSnippet(checkCastTemplate.resolved, receiver, hub);
+        }
+        return new XirSnippet(checkCastTemplate.unresolved, receiver);
     }
 
     @Override
@@ -520,18 +861,18 @@
 
     @Override
     public XirSnippet genGetField(XirSite site, XirArgument receiver, RiField field) {
-        XirPair pair = getStaticFieldTemplates[field.kind().ordinal()];
-        assert field.isResolved() : "getfield doesn't expect unresolved fields";
-        XirArgument offset = XirArgument.forInt(((HotSpotField) field).offset());
-        return new XirSnippet(pair.resolved, receiver, offset);
+        XirPair pair = getFieldTemplates[field.kind().ordinal()];
+        if (field.isResolved()) {
+            return new XirSnippet(pair.resolved, receiver, XirArgument.forInt(((HotSpotField) field).offset()));
+        }
+        return new XirSnippet(pair.unresolved, receiver);
     }
 
     @Override
     public XirSnippet genGetStatic(XirSite site, XirArgument staticTuple, RiField field) {
-        XirPair pair = getStaticFieldTemplates[field.kind().ordinal()];
+        XirPair pair = getStaticTemplates[field.kind().ordinal()];
         if (field.isResolved()) {
-            XirArgument offset = XirArgument.forInt(((HotSpotField) field).offset());
-            return new XirSnippet(pair.resolved, staticTuple, offset);
+            return new XirSnippet(pair.resolved, staticTuple, XirArgument.forInt(((HotSpotField) field).offset()));
         }
         return new XirSnippet(pair.unresolved, staticTuple, null);
     }
@@ -539,17 +880,17 @@
     @Override
     public XirSnippet genPutField(XirSite site, XirArgument receiver, RiField field, XirArgument value) {
         XirPair pair = putFieldTemplates[field.kind().ordinal()];
-        assert field.isResolved() : "putfield doesn't expect unresolved fields";
-        XirArgument offset = XirArgument.forInt(((HotSpotField) field).offset());
-        return new XirSnippet(pair.resolved, receiver, value, offset);
+        if (field.isResolved()) {
+            return new XirSnippet(pair.resolved, receiver, value, XirArgument.forInt(((HotSpotField) field).offset()));
+        }
+        return new XirSnippet(pair.unresolved, receiver, value);
     }
 
     @Override
     public XirSnippet genPutStatic(XirSite site, XirArgument staticTuple, RiField field, XirArgument value) {
-        XirPair pair = putFieldTemplates[field.kind().ordinal()];
+        XirPair pair = putStaticTemplates[field.kind().ordinal()];
         if (field.isResolved()) {
-            XirArgument offset = XirArgument.forInt(((HotSpotField) field).offset());
-            return new XirSnippet(pair.resolved, staticTuple, value, offset);
+            return new XirSnippet(pair.resolved, staticTuple, value, XirArgument.forInt(((HotSpotField) field).offset()));
         }
         return new XirSnippet(pair.unresolved, staticTuple, value);
     }
@@ -559,7 +900,6 @@
         if (type.isResolved()) {
             return new XirSnippet(instanceofTemplate.resolved, receiver, hub);
         }
-        // XirArgument guard = guardFor(type, ResolveClass.SNIPPET);
         return new XirSnippet(instanceofTemplate.unresolved, receiver);
     }
 
@@ -570,12 +910,12 @@
 
     @Override
     public XirSnippet genInvokeInterface(XirSite site, XirArgument receiver, RiMethod method) {
-        return new XirSnippet(invokeInterfaceTemplate, XirArgument.forWord(0));
+        return new XirSnippet(invokeInterfaceTemplate, receiver, XirArgument.forWord(0));
     }
 
     @Override
     public XirSnippet genInvokeSpecial(XirSite site, XirArgument receiver, RiMethod method) {
-        return new XirSnippet(invokeSpecialTemplate, XirArgument.forWord(0));
+        return new XirSnippet(invokeSpecialTemplate, receiver, XirArgument.forWord(0));
     }
 
     @Override
@@ -585,7 +925,7 @@
 
     @Override
     public XirSnippet genInvokeVirtual(XirSite site, XirArgument receiver, RiMethod method) {
-        return new XirSnippet(invokeVirtualTemplate, XirArgument.forWord(0));
+        return new XirSnippet(invokeVirtualTemplate, receiver, XirArgument.forWord(0));
     }
 
     @Override
@@ -600,36 +940,48 @@
 
     @Override
     public XirSnippet genNewArray(XirSite site, XirArgument length, CiKind elementKind, RiType componentType, RiType arrayType) {
-        return new XirSnippet(emptyTemplates[CiKind.Object.ordinal()]);
+        if (elementKind == CiKind.Object) {
+            if (arrayType instanceof HotSpotTypeResolved) {
+                return new XirSnippet(newObjectArrayTemplate.resolved, length, XirArgument.forObject(arrayType));
+            }
+            return new XirSnippet(newObjectArrayTemplate.unresolved, length);
+        }
+        assert arrayType == null;
+        arrayType = Compiler.getVMEntries().getPrimitiveArrayType(elementKind);
+        return new XirSnippet(newTypeArrayTemplate, length, XirArgument.forObject(arrayType));
     }
 
     @Override
     public XirSnippet genNewInstance(XirSite site, RiType type) {
-        assert type instanceof HotSpotTypeResolved;
-        HotSpotTypeResolved resolved = (HotSpotTypeResolved) type;
-        return new XirSnippet(newInstanceTemplate, XirArgument.forObject(type), XirArgument.forWord(resolved.instanceSize()));
+        if (type instanceof HotSpotTypeResolved) {
+            int instanceSize = ((HotSpotTypeResolved) type).instanceSize();
+            return new XirSnippet(newInstanceTemplates.get(instanceSize), XirArgument.forObject(type));
+        }
+        return new XirSnippet(newInstanceUnresolvedTemplate);
     }
 
     @Override
     public XirSnippet genNewMultiArray(XirSite site, XirArgument[] lengths, RiType type) {
-        return new XirSnippet(emptyTemplates[CiKind.Object.ordinal()]);
+        if (type instanceof HotSpotTypeResolved) {
+            XirArgument[] params = Arrays.copyOf(lengths, lengths.length + 1);
+            params[lengths.length] = XirArgument.forObject(type);
+            return new XirSnippet(multiNewArrayTemplate.get(lengths.length).resolved, params);
+        }
+        return new XirSnippet(multiNewArrayTemplate.get(lengths.length).unresolved, lengths);
     }
 
     @Override
     public XirSnippet genResolveClass(XirSite site, RiType type, Representation representation) {
-        XirOperand result = asm.restart(CiKind.Object);
-        if (type.isResolved()) {
-            asm.mov(result, asm.o(type));
-            return new XirSnippet(asm.finishTemplate("resolve class"));
+        assert representation == Representation.ObjectHub;
+        if (type instanceof HotSpotTypeResolved) {
+            return new XirSnippet(resolveClassTemplate.resolved, XirArgument.forObject(type));
         }
-        asm.shouldNotReachHere();
-        return new XirSnippet(asm.finishTemplate("resolve class"));
-
+        return new XirSnippet(resolveClassTemplate.unresolved);
     }
 
     @Override
     public XirSnippet genSafepoint(XirSite site) {
-        return new XirSnippet(emptyTemplates[CiKind.Void.ordinal()]);
+        return new XirSnippet(safepointTemplate);
     }
 
     @Override
@@ -637,4 +989,95 @@
         return new XirSnippet(exceptionObjectTemplate);
     }
 
+    private static class UnresolvedClassPatching {
+
+        private final XirLabel patchSite;
+        private final XirLabel replacement;
+        private final XirLabel patchStub;
+        private final CiXirAssembler asm;
+        private final HotSpotVMConfig config;
+        private final XirOperand arg;
+        private State state;
+
+        private enum State {
+            New, Inline, Finished
+        }
+
+        public UnresolvedClassPatching(CiXirAssembler asm, XirOperand arg, HotSpotVMConfig config) {
+            this.asm = asm;
+            this.arg = arg;
+            this.config = config;
+            patchSite = asm.createInlineLabel("patch site");
+            replacement = asm.createOutOfLineLabel("replacement");
+            patchStub = asm.createOutOfLineLabel("patch stub");
+
+            state = State.New;
+        }
+
+        public void emitInline() {
+            assert state == State.New;
+
+            asm.bindInline(patchSite);
+            asm.mark(MARK_DUMMY_OOP_RELOCATION);
+            asm.jmp(patchStub);
+
+            // TODO: make this more generic & safe - this is needed to create space for patching
+            asm.nop(5);
+
+            state = State.Inline;
+        }
+
+        public void emitOutOfLine() {
+            assert state == State.Inline;
+
+            asm.bindOutOfLine(replacement);
+            XirMark begin = asm.mark(null);
+            asm.mov(arg, asm.createConstant(CiConstant.forObject(null)));
+            XirMark end = asm.mark(null);
+            // make this piece of data look like an instruction
+            asm.rawBytes(new byte[] { (byte) 0xb8, 0, 0, 0x05, 0});
+            asm.mark(MARK_KLASS_PATCHING, begin, end);
+            asm.bindOutOfLine(patchStub);
+            asm.callRuntime(config.loadKlassStub, null);
+            asm.jmp(patchSite);
+
+            state = State.Finished;
+        }
+    }
+
+    private void checkSubtype(XirOperand result, XirOperand objHub, XirOperand hub) {
+        asm.push(objHub);
+        asm.push(hub);
+        asm.callRuntime(config.instanceofStub, null);
+        asm.pop(result);
+        asm.pop(result);
+    }
+
+    private void useRegisters(CiXirAssembler asm, CiRegister... registers) {
+        if (registers != null) {
+            for (CiRegister register : registers) {
+                asm.createRegister("reg", CiKind.Illegal, register);
+            }
+        }
+    }
+
+    private void useRegisters(CiRegister... registers) {
+        useRegisters(asm, registers);
+    }
+
+    private abstract class OndemandTemplates<T> {
+
+        private ConcurrentHashMap<Integer, T> templates = new ConcurrentHashMap<Integer, T>();
+
+        protected abstract T create(CiXirAssembler asm, int index);
+
+        public T get(int index) {
+            T template = templates.get(index);
+            if (template == null) {
+                template = create(asm.copy(), index);
+                templates.put(index, template);
+            }
+            return template;
+        }
+    }
 }