Mercurial > hg > graal-jvmci-8
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; + } + } }