# HG changeset patch # User Stefan Anzinger # Date 1426590351 -3600 # Node ID 825f5c7468bda62d190e37466b172313e068d014 # Parent 8e316bc46018409663db5a3cbb7a96ca50a3ff1f# Parent ab898f9f9c3cc135c6b010062a59726ff92a8e78 Merge diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallsProvider.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallsProvider.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallsProvider.java Tue Mar 17 12:05:51 2015 +0100 @@ -37,8 +37,8 @@ /** * Gets the set of memory locations killed by a given foreign call. Returning the special value - * {@link LocationIdentity#ANY_LOCATION} denotes that the call kills all memory locations. - * Returning any empty array denotes that the call does not kill any memory locations. + * {@link LocationIdentity#any()} denotes that the call kills all memory locations. Returning + * any empty array denotes that the call does not kill any memory locations. */ LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java --- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Tue Mar 17 12:05:51 2015 +0100 @@ -71,6 +71,14 @@ } @Test + public void getLocationIdentityTest() { + for (Map.Entry e : fields.entrySet()) { + LocationIdentity identity = e.getValue().getLocationIdentity(); + assertTrue(identity != null); + } + } + + @Test public void readConstantValueTest() throws NoSuchFieldException { ResolvedJavaField field = metaAccess.lookupJavaField(getClass().getDeclaredField("stringField")); for (Object receiver : new Object[]{this, null, new String()}) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Tue Mar 17 12:05:51 2015 +0100 @@ -33,30 +33,56 @@ * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use * {@link IdentityHashMap}s with {@link LocationIdentity} values as keys. */ -public interface LocationIdentity extends TrustedInterface { +public abstract class LocationIdentity { /** * Denotes any location. A write to such a location kills all values in a memory map during an * analysis of memory accesses. A read from this location cannot be moved or coalesced with * other reads because its interaction with other reads is not known. */ - LocationIdentity ANY_LOCATION = NamedLocationIdentity.mutable("ANY_LOCATION"); + private static final LocationIdentity ANY_LOCATION = NamedLocationIdentity.mutable("ANY_LOCATION"); /** * Denotes the location of a value that is guaranteed to be unchanging. */ - LocationIdentity FINAL_LOCATION = NamedLocationIdentity.immutable("FINAL_LOCATION"); + public static final LocationIdentity FINAL_LOCATION = NamedLocationIdentity.immutable("FINAL_LOCATION"); /** * Denotes the location of the length field of a Java array. */ - LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length"); + public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length"); + + protected final boolean immutable; + + public static LocationIdentity any() { + return ANY_LOCATION; + } + + protected LocationIdentity(boolean immutable) { + this.immutable = immutable; + } /** * Denotes a location is unchanging in all cases. Not that this is different than the Java * notion of final which only requires definite assignment. */ - default boolean isImmutable() { - return false; + public final boolean isImmutable() { + return immutable; + } + + public final boolean isMutable() { + return !immutable; + } + + public final boolean isAny() { + return this == ANY_LOCATION; + } + + public final boolean isSingle() { + return this != ANY_LOCATION; + } + + public final boolean overlaps(LocationIdentity other) { + return isAny() || other.isAny() || this.equals(other); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Tue Mar 17 12:05:51 2015 +0100 @@ -29,7 +29,7 @@ /** * A {@link LocationIdentity} with a name. */ -public final class NamedLocationIdentity implements LocationIdentity, FormatWithToString { +public final class NamedLocationIdentity extends LocationIdentity implements FormatWithToString { /** * Map for asserting all {@link NamedLocationIdentity} instances have a unique name. @@ -48,11 +48,9 @@ protected final String name; - protected final boolean immutable; - private NamedLocationIdentity(String name, boolean immutable) { + super(immutable); this.name = name; - this.immutable = immutable; } /** @@ -89,31 +87,8 @@ } @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (obj instanceof NamedLocationIdentity) { - NamedLocationIdentity that = (NamedLocationIdentity) obj; - boolean res = this.name.equals(that.name); - assert !res || this.immutable == that.immutable; - return res; - } - return false; - } - - @Override public String toString() { - return name + (immutable ? ":immutable" : ":mutable"); - } - - public boolean isImmutable() { - return immutable; + return name + (isImmutable() ? ":immutable" : ":mutable"); } /** diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java Tue Mar 17 12:05:51 2015 +0100 @@ -29,7 +29,7 @@ * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved * through {@link ConstantPool constant pools}. */ -public interface ResolvedJavaField extends JavaField, LocationIdentity, ModifiersProvider { +public interface ResolvedJavaField extends JavaField, ModifiersProvider { /** * {@inheritDoc} @@ -65,4 +65,11 @@ * else {@code null} */ T getAnnotation(Class annotationClass); + + /** + * Returns an object representing the unique location identity of this resolved Java field. + * + * @return the location identity of the field + */ + LocationIdentity getLocationIdentity(); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/BitOpsTest.java --- a/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/BitOpsTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/BitOpsTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,18 @@ package com.oracle.graal.asm.amd64.test; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; import static com.oracle.graal.compiler.common.UnsafeAccess.*; import static org.junit.Assume.*; -import org.junit.*; - import java.lang.reflect.*; import java.util.*; +import org.junit.*; + import com.oracle.graal.amd64.*; -import com.oracle.graal.amd64.AMD64.*; +import com.oracle.graal.amd64.AMD64.CPUFeature; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; @@ -61,7 +63,7 @@ AMD64Assembler asm = new AMD64Assembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Int); Register arg = asRegister(cc.getArgument(0)); - asm.lzcntl(ret, arg); + LZCNT.emit(asm, DWORD, ret, arg); asm.ret(0); return asm.close(true); } @@ -82,7 +84,7 @@ try { Field f = IntField.class.getDeclaredField("x"); AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f)); - asm.lzcntl(ret, arg); + LZCNT.emit(asm, DWORD, ret, arg); asm.ret(0); return asm.close(true); } catch (Exception e) { @@ -104,7 +106,7 @@ AMD64Assembler asm = new AMD64Assembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Int); Register arg = asRegister(cc.getArgument(0)); - asm.lzcntq(ret, arg); + LZCNT.emit(asm, QWORD, ret, arg); asm.ret(0); return asm.close(true); } @@ -125,7 +127,7 @@ try { Field f = LongField.class.getDeclaredField("x"); AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f)); - asm.lzcntq(ret, arg); + LZCNT.emit(asm, QWORD, ret, arg); asm.ret(0); return asm.close(true); } catch (Exception e) { @@ -147,7 +149,7 @@ AMD64Assembler asm = new AMD64Assembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Int); Register arg = asRegister(cc.getArgument(0)); - asm.tzcntl(ret, arg); + TZCNT.emit(asm, DWORD, ret, arg); asm.ret(0); return asm.close(true); } @@ -168,7 +170,7 @@ try { Field f = IntField.class.getDeclaredField("x"); AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f)); - asm.tzcntl(ret, arg); + TZCNT.emit(asm, DWORD, ret, arg); asm.ret(0); return asm.close(true); } catch (Exception e) { @@ -190,7 +192,7 @@ AMD64Assembler asm = new AMD64Assembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Int); Register arg = asRegister(cc.getArgument(0)); - asm.tzcntq(ret, arg); + TZCNT.emit(asm, QWORD, ret, arg); asm.ret(0); return asm.close(true); } @@ -211,7 +213,7 @@ try { Field f = LongField.class.getDeclaredField("x"); AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f)); - asm.tzcntq(ret, arg); + TZCNT.emit(asm, QWORD, ret, arg); asm.ret(0); return asm.close(true); } catch (Exception e) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Tue Mar 17 12:05:51 2015 +0100 @@ -26,10 +26,13 @@ import static com.oracle.graal.api.code.MemoryBarriers.*; import static com.oracle.graal.asm.NumUtil.*; import static com.oracle.graal.asm.amd64.AMD64AsmOptions.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; import com.oracle.graal.amd64.*; import com.oracle.graal.amd64.AMD64.CPUFeature; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Register.RegisterCategory; import com.oracle.graal.asm.*; /** @@ -158,6 +161,131 @@ } /** + * The x86 operand sizes. + */ + public static enum OperandSize { + BYTE(1) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + assert imm == (byte) imm; + asm.emitByte(imm); + } + }, + + WORD(2, 0x66) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + assert imm == (short) imm; + asm.emitShort(imm); + } + }, + + DWORD(4) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + asm.emitInt(imm); + } + }, + + QWORD(8) { + @Override + protected void emitImmediate(AMD64Assembler asm, int imm) { + asm.emitInt(imm); + } + }, + + SS(4, 0xF3, true), + + SD(8, 0xF2, true), + + PS(16, true), + + PD(16, 0x66, true); + + private final int sizePrefix; + + private final int bytes; + private final boolean xmm; + + private OperandSize(int bytes) { + this(bytes, 0); + } + + private OperandSize(int bytes, int sizePrefix) { + this(bytes, sizePrefix, false); + } + + private OperandSize(int bytes, boolean xmm) { + this(bytes, 0, xmm); + } + + private OperandSize(int bytes, int sizePrefix, boolean xmm) { + this.sizePrefix = sizePrefix; + this.bytes = bytes; + this.xmm = xmm; + } + + public int getBytes() { + return bytes; + } + + public boolean isXmmType() { + return xmm; + } + + /** + * Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded + * as sign-extended 32-bit values. + * + * @param asm + * @param imm + */ + protected void emitImmediate(AMD64Assembler asm, int imm) { + assert false; + } + } + + /** + * Operand size and register type constraints. + */ + private static enum OpAssertion { + ByteAssertion(CPU, CPU, BYTE), + IntegerAssertion(CPU, CPU, WORD, DWORD, QWORD), + No16BitAssertion(CPU, CPU, DWORD, QWORD), + QwordOnlyAssertion(CPU, CPU, QWORD), + FloatingAssertion(XMM, XMM, SS, SD, PS, PD), + PackedFloatingAssertion(XMM, XMM, PS, PD), + SingleAssertion(XMM, XMM, SS), + DoubleAssertion(XMM, XMM, SD), + IntToFloatingAssertion(XMM, CPU, DWORD, QWORD), + FloatingToIntAssertion(CPU, XMM, DWORD, QWORD); + + private final RegisterCategory resultCategory; + private final RegisterCategory inputCategory; + private final OperandSize[] allowedSizes; + + private OpAssertion(RegisterCategory resultCategory, RegisterCategory inputCategory, OperandSize... allowedSizes) { + this.resultCategory = resultCategory; + this.inputCategory = inputCategory; + this.allowedSizes = allowedSizes; + } + + protected boolean checkOperands(AMD64Op op, OperandSize size, Register resultReg, Register inputReg) { + assert resultReg == null || resultCategory.equals(resultReg.getRegisterCategory()) : "invalid result register " + resultReg + " used in " + op; + assert inputReg == null || inputCategory.equals(inputReg.getRegisterCategory()) : "invalid input register " + inputReg + " used in " + op; + + for (OperandSize s : allowedSizes) { + if (size == s) { + return true; + } + } + + assert false : "invalid operand size " + size + " used in " + op; + return false; + } + } + + /** * The register to which {@link Register#Frame} and {@link Register#CallerFrame} are bound. */ public final Register frameRegister; @@ -184,97 +312,65 @@ return r.encoding & 0x7; } - private void emitArithImm8(int op, Register dst, int imm8) { - int encode = prefixAndEncode(op, false, dst.encoding, true); - emitByte(0x80); - emitByte(0xC0 | encode); - emitByte(imm8); - } - - private void emitArithImm16(int op, Register dst, int imm16) { - emitByte(0x66); - int encode = prefixAndEncode(op, dst.encoding); - if (isByte(imm16)) { - emitByte(0x83); // imm8 sign extend - emitByte(0xC0 | encode); - emitByte(imm16 & 0xFF); - } else { - emitByte(0x81); - emitByte(0xC0 | encode); - emitShort(imm16); - } - } - - private void emitArithImm32(int op, Register dst, int imm32) { - int encode = prefixAndEncode(op, dst.encoding); - if (isByte(imm32)) { - emitByte(0x83); // imm8 sign extend - emitByte(0xC0 | encode); - emitByte(imm32 & 0xFF); - } else { - emitByte(0x81); - emitByte(0xC0 | encode); - emitInt(imm32); - } - } - - private void emitArithImm32q(int op, Register dst, int imm32) { - emitArithImm32q(op, dst, imm32, false); + /** + * Get RXB bits for register-register instruction. In that encoding, ModRM.rm contains a + * register index. The R bit extends the ModRM.reg field and the B bit extends the ModRM.rm + * field. The X bit must be 0. + */ + protected static int getRXB(Register reg, Register rm) { + int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1; + rxb |= (rm == null ? 0 : rm.encoding & 0x08) >> 3; + return rxb; } - private void emitArithImm32q(int op, Register dst, int imm32, boolean force32Imm) { - int encode = prefixqAndEncode(op, dst.encoding); - if (isByte(imm32) && !force32Imm) { - emitByte(0x83); // imm8 sign extend - emitByte(0xC0 | encode); - emitByte(imm32 & 0xFF); - } else { - emitByte(0x81); - emitByte(0xC0 | encode); - emitInt(imm32); + /** + * Get RXB bits for register-memory instruction. The R bit extends the ModRM.reg field. There + * are two cases for the memory operand:
+ * ModRM.rm contains the base register: In that case, B extends the ModRM.rm field and X = 0.
+ * There is an SIB byte: In that case, X extends SIB.index and B extends SIB.base. + */ + protected static int getRXB(Register reg, AMD64Address rm) { + int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1; + if (!rm.getIndex().equals(Register.None)) { + rxb |= (rm.getIndex().encoding & 0x08) >> 2; } - } - - // immediate-to-memory forms - private void emitArithImm8(int op, AMD64Address adr, int imm8) { - prefix(adr); - emitByte(0x80); - emitOperandHelper(op, adr); - emitByte(imm8); + if (!rm.getBase().equals(Register.None)) { + rxb |= (rm.getBase().encoding & 0x08) >> 3; + } + return rxb; } - private void emitArithImm16(int op, AMD64Address adr, int imm16) { - emitByte(0x66); - prefix(adr); - if (isByte(imm16)) { - emitByte(0x83); // imm8 sign extend - emitOperandHelper(op, adr); - emitByte(imm16 & 0xFF); - } else { - emitByte(0x81); - emitOperandHelper(op, adr); - emitShort(imm16); - } + /** + * Emit the ModR/M byte for one register operand and an opcode extension in the R field. + *

+ * Format: [ 11 reg r/m ] + */ + protected void emitModRM(int reg, Register rm) { + assert (reg & 0x07) == reg; + emitByte(0xC0 | (reg << 3) | (rm.encoding & 0x07)); } - private void emitArithImm32(int op, AMD64Address adr, int imm32) { - prefix(adr); - if (isByte(imm32)) { - emitByte(0x83); // imm8 sign extend - emitOperandHelper(op, adr); - emitByte(imm32 & 0xFF); - } else { - emitByte(0x81); - emitOperandHelper(op, adr); - emitInt(imm32); - } + /** + * Emit the ModR/M byte for two register operands. + *

+ * Format: [ 11 reg r/m ] + */ + protected void emitModRM(Register reg, Register rm) { + emitModRM(reg.encoding & 0x07, rm); } + /** + * Emits the ModR/M byte and optionally the SIB byte for one register and one memory operand. + */ protected void emitOperandHelper(Register reg, AMD64Address addr) { assert !reg.equals(Register.None); emitOperandHelper(encode(reg), addr); } + /** + * Emits the ModR/M byte and optionally the SIB byte for one memory operand and an opcode + * extension in the R field. + */ protected void emitOperandHelper(int reg, AMD64Address addr) { assert (reg & 0x07) == reg; int regenc = reg << 3; @@ -379,24 +475,470 @@ } } + /** + * Base class for AMD64 opcodes. + */ + public static class AMD64Op { + + protected static final int P_0F = 0x0F; + protected static final int P_0F38 = 0x380F; + protected static final int P_0F3A = 0x3A0F; + + private final String opcode; + + private final int prefix1; + private final int prefix2; + private final int op; + + private final boolean dstIsByte; + private final boolean srcIsByte; + + private final OpAssertion assertion; + private final CPUFeature feature; + + protected AMD64Op(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + this(opcode, prefix1, prefix2, op, assertion == OpAssertion.ByteAssertion, assertion == OpAssertion.ByteAssertion, assertion, feature); + } + + protected AMD64Op(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) { + this.opcode = opcode; + this.prefix1 = prefix1; + this.prefix2 = prefix2; + this.op = op; + + this.dstIsByte = dstIsByte; + this.srcIsByte = srcIsByte; + + this.assertion = assertion; + this.feature = feature; + } + + protected final void emitOpcode(AMD64Assembler asm, OperandSize size, int rxb, int dstEnc, int srcEnc) { + if (prefix1 != 0) { + asm.emitByte(prefix1); + } + if (size.sizePrefix != 0) { + asm.emitByte(size.sizePrefix); + } + int rexPrefix = 0x40 | rxb; + if (size == QWORD) { + rexPrefix |= 0x08; + } + if (rexPrefix != 0x40 || (dstIsByte && dstEnc >= 4) || (srcIsByte && srcEnc >= 4)) { + asm.emitByte(rexPrefix); + } + if (prefix2 > 0xFF) { + asm.emitShort(prefix2); + } else if (prefix2 > 0) { + asm.emitByte(prefix2); + } + asm.emitByte(op); + } + + protected final boolean verify(AMD64Assembler asm, OperandSize size, Register resultReg, Register inputReg) { + assert feature == null || asm.supports(feature) : String.format("unsupported feature %s required for %s", feature, opcode); + assert assertion.checkOperands(this, size, resultReg, inputReg); + return true; + } + + @Override + public String toString() { + return opcode; + } + } + + /** + * Base class for AMD64 opcodes with immediate operands. + */ + public static class AMD64ImmOp extends AMD64Op { + + private final boolean immIsByte; + + protected AMD64ImmOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) { + super(opcode, 0, prefix, op, assertion, null); + this.immIsByte = immIsByte; + } + + protected final void emitImmediate(AMD64Assembler asm, OperandSize size, int imm) { + if (immIsByte) { + assert imm == (byte) imm; + asm.emitByte(imm); + } else { + size.emitImmediate(asm, imm); + } + } + } + + /** + * Opcode with operand order of either RM or MR. + */ + public abstract static class AMD64RROp extends AMD64Op { + + protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + protected AMD64RROp(String opcode, int prefix1, int prefix2, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, dstIsByte, srcIsByte, assertion, feature); + } + + public abstract void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src); + } + + /** + * Opcode with operand order of RM. + */ + public static class AMD64RMOp extends AMD64RROp { + // @formatter:off + public static final AMD64RMOp IMUL = new AMD64RMOp("IMUL", P_0F, 0xAF); + public static final AMD64RMOp BSF = new AMD64RMOp("BSF", P_0F, 0xBC); + public static final AMD64RMOp BSR = new AMD64RMOp("BSR", P_0F, 0xBD); + public static final AMD64RMOp POPCNT = new AMD64RMOp("POPCNT", 0xF3, P_0F, 0xB8, CPUFeature.POPCNT); + public static final AMD64RMOp TZCNT = new AMD64RMOp("TZCNT", 0xF3, P_0F, 0xBC, CPUFeature.BMI1); + public static final AMD64RMOp LZCNT = new AMD64RMOp("LZCNT", 0xF3, P_0F, 0xBD, CPUFeature.LZCNT); + public static final AMD64RMOp MOVZXB = new AMD64RMOp("MOVZXB", P_0F, 0xB6, false, true, OpAssertion.IntegerAssertion); + public static final AMD64RMOp MOVZX = new AMD64RMOp("MOVZX", P_0F, 0xB7, OpAssertion.No16BitAssertion); + public static final AMD64RMOp MOVSXB = new AMD64RMOp("MOVSXB", P_0F, 0xBE, false, true, OpAssertion.IntegerAssertion); + public static final AMD64RMOp MOVSX = new AMD64RMOp("MOVSX", P_0F, 0xBF, OpAssertion.No16BitAssertion); + public static final AMD64RMOp MOVSXD = new AMD64RMOp("MOVSXD", 0x63, OpAssertion.QwordOnlyAssertion); + public static final AMD64RMOp MOV = new AMD64RMOp("MOV", 0x8B); + + // MOVD and MOVQ are the same opcode, just with different operand size prefix + public static final AMD64RMOp MOVD = new AMD64RMOp("MOVD", 0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + public static final AMD64RMOp MOVQ = new AMD64RMOp("MOVQ", 0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + + // TEST is documented as MR operation, but it's symmetric, and using it as RM operation is more convenient. + public static final AMD64RMOp TESTB = new AMD64RMOp("TEST", 0x84, OpAssertion.ByteAssertion); + public static final AMD64RMOp TEST = new AMD64RMOp("TEST", 0x85); + // @formatter:on + + protected AMD64RMOp(String opcode, int op) { + this(opcode, 0, op); + } + + protected AMD64RMOp(String opcode, int op, OpAssertion assertion) { + this(opcode, 0, op, assertion); + } + + protected AMD64RMOp(String opcode, int prefix, int op) { + this(opcode, 0, prefix, op, null); + } + + protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, 0, prefix, op, assertion, null); + } + + protected AMD64RMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) { + super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null); + } + + protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, CPUFeature feature) { + this(opcode, prefix1, prefix2, op, OpAssertion.IntegerAssertion, feature); + } + + protected AMD64RMOp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + @Override + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) { + assert verify(asm, size, dst, src); + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding); + asm.emitModRM(dst, src); + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src) { + assert verify(asm, size, dst, null); + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0); + asm.emitOperandHelper(dst, src); + } + } + + /** + * Opcode with operand order of MR. + */ + public static class AMD64MROp extends AMD64RROp { + // @formatter:off + public static final AMD64MROp MOV = new AMD64MROp("MOV", 0x89); + + // MOVD and MOVQ are the same opcode, just with different operand size prefix + // Note that as MR opcodes, they have reverse operand order, so the IntToFloatingAssertion must be used. + public static final AMD64MROp MOVD = new AMD64MROp("MOVD", 0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + public static final AMD64MROp MOVQ = new AMD64MROp("MOVQ", 0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + // @formatter:on + + protected AMD64MROp(String opcode, int op) { + this(opcode, 0, op); + } + + protected AMD64MROp(String opcode, int op, OpAssertion assertion) { + this(opcode, 0, op, assertion); + } + + protected AMD64MROp(String opcode, int prefix, int op) { + this(opcode, prefix, op, OpAssertion.IntegerAssertion); + } + + protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, 0, prefix, op, assertion, null); + } + + protected AMD64MROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { + super(opcode, prefix1, prefix2, op, assertion, feature); + } + + @Override + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src) { + assert verify(asm, size, src, dst); + emitOpcode(asm, size, getRXB(src, dst), src.encoding, dst.encoding); + asm.emitModRM(src, dst); + } + + public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, Register src) { + assert verify(asm, size, null, src); + emitOpcode(asm, size, getRXB(src, dst), src.encoding, 0); + asm.emitOperandHelper(src, dst); + } + } + + /** + * Opcodes with operand order of M. + */ + public static class AMD64MOp extends AMD64Op { + // @formatter:off + public static final AMD64MOp NOT = new AMD64MOp("NOT", 0xF7, 2); + public static final AMD64MOp NEG = new AMD64MOp("NEG", 0xF7, 3); + public static final AMD64MOp MUL = new AMD64MOp("MUL", 0xF7, 4); + public static final AMD64MOp IMUL = new AMD64MOp("IMUL", 0xF7, 5); + public static final AMD64MOp DIV = new AMD64MOp("DIV", 0xF7, 6); + public static final AMD64MOp IDIV = new AMD64MOp("IDIV", 0xF7, 7); + // @formatter:on + + private final int ext; + + protected AMD64MOp(String opcode, int op, int ext) { + this(opcode, 0, op, ext); + } + + protected AMD64MOp(String opcode, int prefix, int op, int ext) { + this(opcode, prefix, op, ext, OpAssertion.IntegerAssertion); + } + + protected AMD64MOp(String opcode, int prefix, int op, int ext, OpAssertion assertion) { + super(opcode, 0, prefix, op, assertion, null); + this.ext = ext; + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst) { + assert verify(asm, size, dst, null); + emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding); + asm.emitModRM(ext, dst); + } + + public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst) { + assert verify(asm, size, null, null); + emitOpcode(asm, size, getRXB(null, dst), 0, 0); + asm.emitOperandHelper(ext, dst); + } + } + + /** + * Opcodes with operand order of MI. + */ + public static class AMD64MIOp extends AMD64ImmOp { + // @formatter:off + public static final AMD64MIOp MOV = new AMD64MIOp("MOV", false, 0xC7, 0); + public static final AMD64MIOp TEST = new AMD64MIOp("TEST", false, 0xF7, 0); + // @formatter:on + + private final int ext; + + protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext) { + this(opcode, immIsByte, 0, op, ext, OpAssertion.IntegerAssertion); + } + + protected AMD64MIOp(String opcode, boolean immIsByte, int prefix, int op, int ext, OpAssertion assertion) { + super(opcode, immIsByte, prefix, op, assertion); + this.ext = ext; + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, int imm) { + assert verify(asm, size, dst, null); + emitOpcode(asm, size, getRXB(null, dst), 0, dst.encoding); + asm.emitModRM(ext, dst); + emitImmediate(asm, size, imm); + } + + public final void emit(AMD64Assembler asm, OperandSize size, AMD64Address dst, int imm) { + assert verify(asm, size, null, null); + emitOpcode(asm, size, getRXB(null, dst), 0, 0); + asm.emitOperandHelper(ext, dst); + emitImmediate(asm, size, imm); + } + } + + /** + * Opcodes with operand order of RMI. + */ + public static class AMD64RMIOp extends AMD64ImmOp { + // @formatter:off + public static final AMD64RMIOp IMUL = new AMD64RMIOp("IMUL", false, 0x69); + public static final AMD64RMIOp IMUL_SX = new AMD64RMIOp("IMUL", true, 0x6B); + // @formatter:on + + protected AMD64RMIOp(String opcode, boolean immIsByte, int op) { + this(opcode, immIsByte, 0, op, OpAssertion.IntegerAssertion); + } + + protected AMD64RMIOp(String opcode, boolean immIsByte, int prefix, int op, OpAssertion assertion) { + super(opcode, immIsByte, prefix, op, assertion); + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, Register src, int imm) { + assert verify(asm, size, dst, src); + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, src.encoding); + asm.emitModRM(dst, src); + emitImmediate(asm, size, imm); + } + + public final void emit(AMD64Assembler asm, OperandSize size, Register dst, AMD64Address src, int imm) { + assert verify(asm, size, dst, null); + emitOpcode(asm, size, getRXB(dst, src), dst.encoding, 0); + asm.emitOperandHelper(dst, src); + emitImmediate(asm, size, imm); + } + } + + public static class SSEOp extends AMD64RMOp { + // @formatter:off + public static final SSEOp CVTSI2SS = new SSEOp("CVTSI2SS", 0xF3, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion); + public static final SSEOp CVTSI2SD = new SSEOp("CVTSI2SS", 0xF2, P_0F, 0x2A, OpAssertion.IntToFloatingAssertion); + public static final SSEOp CVTTSS2SI = new SSEOp("CVTTSS2SI", 0xF3, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion); + public static final SSEOp CVTTSD2SI = new SSEOp("CVTTSD2SI", 0xF2, P_0F, 0x2C, OpAssertion.FloatingToIntAssertion); + public static final SSEOp UCOMIS = new SSEOp("UCOMIS", P_0F, 0x2E, OpAssertion.PackedFloatingAssertion); + public static final SSEOp SQRT = new SSEOp("SQRT", P_0F, 0x51); + public static final SSEOp AND = new SSEOp("AND", P_0F, 0x54, OpAssertion.PackedFloatingAssertion); + public static final SSEOp ANDN = new SSEOp("ANDN", P_0F, 0x55, OpAssertion.PackedFloatingAssertion); + public static final SSEOp OR = new SSEOp("OR", P_0F, 0x56, OpAssertion.PackedFloatingAssertion); + public static final SSEOp XOR = new SSEOp("XOR", P_0F, 0x57, OpAssertion.PackedFloatingAssertion); + public static final SSEOp ADD = new SSEOp("ADD", P_0F, 0x58); + public static final SSEOp MUL = new SSEOp("MUL", P_0F, 0x59); + public static final SSEOp CVTSS2SD = new SSEOp("CVTSS2SD", P_0F, 0x5A, OpAssertion.SingleAssertion); + public static final SSEOp CVTSD2SS = new SSEOp("CVTSD2SS", P_0F, 0x5A, OpAssertion.DoubleAssertion); + public static final SSEOp SUB = new SSEOp("SUB", P_0F, 0x5C); + public static final SSEOp MIN = new SSEOp("MIN", P_0F, 0x5D); + public static final SSEOp DIV = new SSEOp("DIV", P_0F, 0x5E); + public static final SSEOp MAX = new SSEOp("MAX", P_0F, 0x5F); + // @formatter:on + + protected SSEOp(String opcode, int prefix, int op) { + this(opcode, prefix, op, OpAssertion.FloatingAssertion); + } + + protected SSEOp(String opcode, int prefix, int op, OpAssertion assertion) { + this(opcode, 0, prefix, op, assertion); + } + + protected SSEOp(String opcode, int mandatoryPrefix, int prefix, int op, OpAssertion assertion) { + super(opcode, mandatoryPrefix, prefix, op, assertion, CPUFeature.SSE2); + } + } + + /** + * Arithmetic operation with operand order of RM, MR or MI. + */ + public static final class AMD64BinaryArithmetic { + // @formatter:off + public static final AMD64BinaryArithmetic ADD = new AMD64BinaryArithmetic("ADD", 0); + public static final AMD64BinaryArithmetic OR = new AMD64BinaryArithmetic("OR", 1); + public static final AMD64BinaryArithmetic ADC = new AMD64BinaryArithmetic("ADC", 2); + public static final AMD64BinaryArithmetic SBB = new AMD64BinaryArithmetic("SBB", 3); + public static final AMD64BinaryArithmetic AND = new AMD64BinaryArithmetic("AND", 4); + public static final AMD64BinaryArithmetic SUB = new AMD64BinaryArithmetic("SUB", 5); + public static final AMD64BinaryArithmetic XOR = new AMD64BinaryArithmetic("XOR", 6); + public static final AMD64BinaryArithmetic CMP = new AMD64BinaryArithmetic("CMP", 7); + // @formatter:on + + private final AMD64MIOp byteImmOp; + private final AMD64MROp byteMrOp; + private final AMD64RMOp byteRmOp; + + private final AMD64MIOp immOp; + private final AMD64MIOp immSxOp; + private final AMD64MROp mrOp; + private final AMD64RMOp rmOp; + + private AMD64BinaryArithmetic(String opcode, int code) { + int baseOp = code << 3; + + byteImmOp = new AMD64MIOp(opcode, true, 0, 0x80, code, OpAssertion.ByteAssertion); + byteMrOp = new AMD64MROp(opcode, 0, baseOp, OpAssertion.ByteAssertion); + byteRmOp = new AMD64RMOp(opcode, 0, baseOp | 0x02, OpAssertion.ByteAssertion); + + immOp = new AMD64MIOp(opcode, false, 0, 0x81, code, OpAssertion.IntegerAssertion); + immSxOp = new AMD64MIOp(opcode, true, 0, 0x83, code, OpAssertion.IntegerAssertion); + mrOp = new AMD64MROp(opcode, 0, baseOp | 0x01, OpAssertion.IntegerAssertion); + rmOp = new AMD64RMOp(opcode, 0, baseOp | 0x03, OpAssertion.IntegerAssertion); + } + + public AMD64MIOp getMIOpcode(OperandSize size, boolean sx) { + if (size == BYTE) { + return byteImmOp; + } else if (sx) { + return immSxOp; + } else { + return immOp; + } + } + + public AMD64MROp getMROpcode(OperandSize size) { + if (size == BYTE) { + return byteMrOp; + } else { + return mrOp; + } + } + + public AMD64RMOp getRMOpcode(OperandSize size) { + if (size == BYTE) { + return byteRmOp; + } else { + return rmOp; + } + } + } + + /** + * Shift operation with operand order of M1, MC or MI. + */ + public static final class AMD64Shift { + // @formatter:off + public static final AMD64Shift ROL = new AMD64Shift("ROL", 0); + public static final AMD64Shift ROR = new AMD64Shift("ROR", 1); + public static final AMD64Shift RCL = new AMD64Shift("RCL", 2); + public static final AMD64Shift RCR = new AMD64Shift("RCR", 3); + public static final AMD64Shift SHL = new AMD64Shift("SHL", 4); + public static final AMD64Shift SHR = new AMD64Shift("SHR", 5); + public static final AMD64Shift SAR = new AMD64Shift("SAR", 7); + // @formatter:on + + public final AMD64MOp m1Op; + public final AMD64MOp mcOp; + public final AMD64MIOp miOp; + + private AMD64Shift(String opcode, int code) { + m1Op = new AMD64MOp(opcode, 0, 0xD1, code, OpAssertion.IntegerAssertion); + mcOp = new AMD64MOp(opcode, 0, 0xD3, code, OpAssertion.IntegerAssertion); + miOp = new AMD64MIOp(opcode, true, 0, 0xC1, code, OpAssertion.IntegerAssertion); + } + } + public final void addl(AMD64Address dst, int imm32) { - emitArithImm32(0, dst, imm32); + ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } public final void addl(Register dst, int imm32) { - emitArithImm32(0, dst, imm32); - } - - public final void addl(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x03); - emitOperandHelper(dst, src); - } - - public final void addl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x03); - emitByte(0xC0 | encode); + ADD.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } private void addrNop4() { @@ -433,98 +975,8 @@ emitInt(0); // 32-bits offset (4 bytes) } - public final void addsd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x58); - emitByte(0xC0 | encode); - } - - public final void addsd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x58); - emitOperandHelper(dst, src); - } - - public final void addss(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x58); - emitByte(0xC0 | encode); - } - - public final void addss(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x58); - emitOperandHelper(dst, src); - } - public final void andl(Register dst, int imm32) { - emitArithImm32(4, dst, imm32); - } - - public final void andl(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x23); - emitOperandHelper(dst, src); - } - - public final void andl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x23); - emitByte(0xC0 | encode); - } - - public final void bsfq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBC); - emitByte(0xC0 | encode); - } - - public final void bsfq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xBC); - emitOperandHelper(dst, src); - } - - public final void bsrq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBD); - emitByte(0xC0 | encode); - } - - public final void bsrq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xBD); - emitOperandHelper(dst, src); - } - - public final void bsrl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBD); - emitByte(0xC0 | encode); - } - - public final void bsrl(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x0F); - emitByte(0xBD); - emitOperandHelper(dst, src); + AND.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } public final void bswapl(Register reg) { @@ -551,66 +1003,20 @@ emitOperandHelper(dst, src); } - public final void cmpb(Register dst, int imm8) { - emitArithImm8(7, dst, imm8); - } - - public final void cmpb(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, true, src.encoding, true); - emitByte(0x3A); - emitByte(0xC0 | encode); - } - - public final void cmpb(Register dst, AMD64Address src) { - prefix(src, dst, true); - emitByte(0x3A); - emitOperandHelper(dst, src); - } - - public final void cmpb(AMD64Address dst, int imm8) { - emitArithImm8(7, dst, imm8); - } - - public final void cmpw(Register dst, int imm16) { - emitArithImm16(7, dst, imm16); - } - - public final void cmpw(Register dst, Register src) { - emitByte(0x66); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x3B); - emitByte(0xC0 | encode); - } - - public final void cmpw(Register dst, AMD64Address src) { - emitByte(0x66); - prefix(src, dst); - emitByte(0x3B); - emitOperandHelper(dst, src); - } - - public final void cmpw(AMD64Address dst, int imm16) { - emitArithImm16(7, dst, imm16); - } - public final void cmpl(Register dst, int imm32) { - emitArithImm32(7, dst, imm32); + CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } public final void cmpl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x3B); - emitByte(0xC0 | encode); + CMP.rmOp.emit(this, DWORD, dst, src); } public final void cmpl(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x3B); - emitOperandHelper(dst, src); + CMP.rmOp.emit(this, DWORD, dst, src); } public final void cmpl(AMD64Address dst, int imm32) { - emitArithImm32(7, dst, imm32); + CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax, @@ -623,235 +1029,21 @@ emitOperandHelper(reg, adr); } - public final void cvtsd2ss(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x5A); - emitOperandHelper(dst, src); - } - - public final void cvtsd2ss(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x5A); - emitByte(0xC0 | encode); - } - - public final void cvtsi2sdl(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x2A); - emitOperandHelper(dst, src); - } - - public final void cvtsi2sdl(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2A); - emitByte(0xC0 | encode); - } - - public final void cvtsi2ssl(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x2A); - emitOperandHelper(dst, src); - } - - public final void cvtsi2ssl(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2A); - emitByte(0xC0 | encode); - } - - public final void cvtss2sd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x5A); - emitOperandHelper(dst, src); - } - - public final void cvtss2sd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x5A); - emitByte(0xC0 | encode); - } - - public final void cvttsd2sil(Register dst, AMD64Address src) { - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x2C); - emitOperandHelper(dst, src); - } - - public final void cvttsd2sil(Register dst, Register src) { - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2C); - emitByte(0xC0 | encode); - } - - public final void cvttss2sil(Register dst, AMD64Address src) { - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x2C); - emitOperandHelper(dst, src); - } - - public final void cvttss2sil(Register dst, Register src) { - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2C); - emitByte(0xC0 | encode); - } - protected final void decl(AMD64Address dst) { prefix(dst); emitByte(0xFF); emitOperandHelper(1, dst); } - public final void divsd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x5E); - emitOperandHelper(dst, src); - } - - public final void divsd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x5E); - emitByte(0xC0 | encode); - } - - public final void divss(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x5E); - emitOperandHelper(dst, src); - } - - public final void divss(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x5E); - emitByte(0xC0 | encode); - } - public final void hlt() { emitByte(0xF4); } - public final void idivl(Register src) { - int encode = prefixAndEncode(7, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void divl(Register src) { - int encode = prefixAndEncode(6, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void mull(Register src) { - int encode = prefixAndEncode(4, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void mull(AMD64Address src) { - prefix(src); - emitByte(0xF7); - emitOperandHelper(4, src); - } - - public final void imull(Register src) { - int encode = prefixAndEncode(5, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void imull(AMD64Address src) { - prefix(src); - emitByte(0xF7); - emitOperandHelper(5, src); - } - - public final void imull(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xAF); - emitByte(0xC0 | encode); - } - - public final void imull(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x0F); - emitByte(0xAF); - emitOperandHelper(dst, src); - } - public final void imull(Register dst, Register src, int value) { - int encode = prefixAndEncode(dst.encoding, src.encoding); if (isByte(value)) { - emitByte(0x6B); - emitByte(0xC0 | encode); - emitByte(value & 0xFF); + AMD64RMIOp.IMUL_SX.emit(this, DWORD, dst, src, value); } else { - emitByte(0x69); - emitByte(0xC0 | encode); - emitInt(value); - } - } - - public final void imull(Register dst, AMD64Address src, int value) { - prefix(src, dst); - if (isByte(value)) { - emitByte(0x6B); - emitOperandHelper(dst, src); - emitByte(value & 0xFF); - } else { - emitByte(0x69); - emitOperandHelper(dst, src); - emitInt(value); + AMD64RMIOp.IMUL.emit(this, DWORD, dst, src, value); } } @@ -1039,25 +1231,6 @@ emitOperandHelper(src, dst); } - public final void movdl(Register dst, Register src) { - if (dst.getRegisterCategory().equals(AMD64.XMM)) { - assert !src.getRegisterCategory().equals(AMD64.XMM) : "does this hold?"; - emitByte(0x66); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x6E); - emitByte(0xC0 | encode); - } else if (src.getRegisterCategory().equals(AMD64.XMM)) { - assert !dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0x66); - // swap src/dst to get correct prefix - int encode = prefixAndEncode(src.encoding, dst.encoding); - emitByte(0x0F); - emitByte(0x7E); - emitByte(0xC0 | encode); - } - } - public final void movl(Register dst, int imm32) { int encode = prefixAndEncode(dst.encoding); emitByte(0xB8 | encode); @@ -1229,27 +1402,6 @@ emitOperandHelper(dst, src); } - public final void movswl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBF); - emitByte(0xC0 | encode); - } - - public final void movswq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xBF); - emitOperandHelper(dst, src); - } - - public final void movswq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBF); - emitByte(0xC0 | encode); - } - public final void movw(AMD64Address dst, int imm16) { emitByte(0x66); // switch to 16-bit mode prefix(dst); @@ -1279,99 +1431,11 @@ emitOperandHelper(dst, src); } - public final void mulsd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x59); - emitOperandHelper(dst, src); - } - - public final void mulsd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x59); - emitByte(0xC0 | encode); - } - - public final void mulss(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x59); - emitOperandHelper(dst, src); - } - - public final void mulss(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x59); - emitByte(0xC0 | encode); - } - - public final void negl(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xF7); - emitByte(0xD8 | encode); - } - - public final void notl(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xF7); - emitByte(0xD0 | encode); - } - @Override public final void ensureUniquePC() { nop(); } - public final void lzcntl(Register dst, Register src) { - assert supports(CPUFeature.LZCNT); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBD); - emitByte(0xC0 | encode); - } - - public final void lzcntq(Register dst, Register src) { - assert supports(CPUFeature.LZCNT); - emitByte(0xF3); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBD); - emitByte(0xC0 | encode); - } - - public final void lzcntl(Register dst, AMD64Address src) { - assert supports(CPUFeature.LZCNT); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0xBD); - emitOperandHelper(dst, src); - } - - public final void lzcntq(Register dst, AMD64Address src) { - assert supports(CPUFeature.LZCNT); - emitByte(0xF3); - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xBD); - emitOperandHelper(dst, src); - } - public final void nop() { nop(1); } @@ -1578,58 +1642,6 @@ } } - public final void orl(Register dst, int imm32) { - emitArithImm32(1, dst, imm32); - } - - public final void orl(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x0B); - emitOperandHelper(dst, src); - } - - public final void orl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0B); - emitByte(0xC0 | encode); - } - - public final void popcntl(Register dst, AMD64Address src) { - assert supports(CPUFeature.POPCNT); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0xB8); - emitOperandHelper(dst, src); - } - - public final void popcntl(Register dst, Register src) { - assert supports(CPUFeature.POPCNT); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xB8); - emitByte(0xC0 | encode); - } - - public final void popcntq(Register dst, AMD64Address src) { - assert supports(CPUFeature.POPCNT); - emitByte(0xF3); - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xB8); - emitOperandHelper(dst, src); - } - - public final void popcntq(Register dst, Register src) { - assert supports(CPUFeature.POPCNT); - emitByte(0xF3); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xB8); - emitByte(0xC0 | encode); - } - public final void pop(Register dst) { int encode = prefixAndEncode(dst.encoding); emitByte(0x58 | encode); @@ -1675,218 +1687,12 @@ } } - public final void sarl(Register dst, int imm8) { - int encode = prefixAndEncode(dst.encoding); - assert isShiftCount(imm8) : "illegal shift count"; - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xF8 | encode); - } else { - emitByte(0xC1); - emitByte(0xF8 | encode); - emitByte(imm8); - } - } - - public final void sarl(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xF8 | encode); - } - - public final void shll(Register dst, int imm8) { - assert isShiftCount(imm8) : "illegal shift count"; - int encode = prefixAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xE0 | encode); - } else { - emitByte(0xC1); - emitByte(0xE0 | encode); - emitByte(imm8); - } - } - - public final void shll(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xE0 | encode); - } - - public final void shrl(Register dst, int imm8) { - assert isShiftCount(imm8) : "illegal shift count"; - int encode = prefixAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xE8 | encode); - } else { - emitByte(0xC1); - emitByte(0xE8 | encode); - emitByte(imm8); - } - } - - public final void shrl(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xE8 | encode); - } - - public final void roll(Register dst, int imm8) { - assert isShiftCount(imm8) : "illegal shift count"; - int encode = prefixAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xC0 | encode); - } else { - emitByte(0xC1); - emitByte(0xC0 | encode); - emitByte(imm8); - } - } - - public final void roll(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xC0 | encode); - } - - public final void rorl(Register dst, int imm8) { - assert isShiftCount(imm8) : "illegal shift count"; - int encode = prefixAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xC8 | encode); - } else { - emitByte(0xC1); - emitByte(0xC8 | encode); - emitByte(imm8); - } - } - - public final void rorl(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xC8 | encode); - } - - public final void rolq(Register dst, int imm8) { - assert isShiftCount(imm8) : "illegal shift count"; - int encode = prefixqAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xC0 | encode); - } else { - emitByte(0xC1); - emitByte(0xC0 | encode); - emitByte(imm8); - } - } - - public final void rolq(Register dst) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xC0 | encode); - } - - public final void rorq(Register dst, int imm8) { - assert isShiftCount(imm8) : "illegal shift count"; - int encode = prefixqAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xC8 | encode); - } else { - emitByte(0xC1); - emitByte(0xC8 | encode); - emitByte(imm8); - } - } - - public final void rorq(Register dst) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xC8 | encode); - } - - public final void sqrtsd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x51); - emitOperandHelper(dst, src); - } - - public final void sqrtsd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - // HMM Table D-1 says sse2 - // assert is64 || target.supportsSSE(); - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x51); - emitByte(0xC0 | encode); - } - public final void subl(AMD64Address dst, int imm32) { - emitArithImm32(5, dst, imm32); + SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } public final void subl(Register dst, int imm32) { - emitArithImm32(5, dst, imm32); - } - - public final void subl(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x2B); - emitOperandHelper(dst, src); - } - - public final void subl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x2B); - emitByte(0xC0 | encode); - } - - public final void subsd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x5C); - emitByte(0xC0 | encode); - } - - public final void subsd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x5C); - emitOperandHelper(dst, src); - } - - public final void subss(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x5C); - emitByte(0xC0 | encode); - } - - public final void subss(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x5C); - emitOperandHelper(dst, src); + SUB.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } public final void testl(Register dst, int imm32) { @@ -1904,13 +1710,6 @@ emitInt(imm32); } - public final void testl(AMD64Address dst, int imm32) { - prefix(dst); - emitByte(0xF7); - emitOperandHelper(0, dst); - emitInt(imm32); - } - public final void testl(Register dst, Register src) { int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x85); @@ -1923,139 +1722,8 @@ emitOperandHelper(dst, src); } - public final void tzcntl(Register dst, Register src) { - assert supports(CPUFeature.BMI1); - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBC); - emitByte(0xC0 | encode); - } - - public final void tzcntq(Register dst, Register src) { - assert supports(CPUFeature.BMI1); - emitByte(0xF3); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBC); - emitByte(0xC0 | encode); - } - - public final void tzcntl(Register dst, AMD64Address src) { - assert supports(CPUFeature.BMI1); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0xBC); - emitOperandHelper(dst, src); - } - - public final void tzcntq(Register dst, AMD64Address src) { - assert supports(CPUFeature.BMI1); - emitByte(0xF3); - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xBC); - emitOperandHelper(dst, src); - } - - public final void ucomisd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0x66); - ucomiss(dst, src); - } - - public final void ucomisd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0x66); - ucomiss(dst, src); - } - - public final void ucomiss(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - - prefix(src, dst); - emitByte(0x0F); - emitByte(0x2E); - emitOperandHelper(dst, src); - } - - public final void ucomiss(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - assert src.getRegisterCategory().equals(AMD64.XMM); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2E); - emitByte(0xC0 | encode); - } - - public final void xorl(Register dst, int imm32) { - emitArithImm32(6, dst, imm32); - } - - public final void xorl(Register dst, AMD64Address src) { - prefix(src, dst); - emitByte(0x33); - emitOperandHelper(dst, src); - } - public final void xorl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x33); - emitByte(0xC0 | encode); - } - - public final void andpd(Register dst, Register src) { - emitByte(0x66); - andps(dst, src); - } - - public final void andpd(Register dst, AMD64Address src) { - emitByte(0x66); - andps(dst, src); - } - - public final void andps(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x54); - emitByte(0xC0 | encode); - } - - public final void andps(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x54); - emitOperandHelper(dst, src); - } - - public final void orpd(Register dst, Register src) { - emitByte(0x66); - orps(dst, src); - } - - public final void orpd(Register dst, AMD64Address src) { - emitByte(0x66); - orps(dst, src); - } - - public final void orps(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x56); - emitByte(0xC0 | encode); - } - - public final void orps(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x56); - emitOperandHelper(dst, src); + XOR.rmOp.emit(this, DWORD, dst, src); } public final void xorpd(Register dst, Register src) { @@ -2063,11 +1731,6 @@ xorps(dst, src); } - public final void xorpd(Register dst, AMD64Address src) { - emitByte(0x66); - xorps(dst, src); - } - public final void xorps(Register dst, Register src) { assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); int encode = prefixAndEncode(dst.encoding, src.encoding); @@ -2076,14 +1739,6 @@ emitByte(0xC0 | encode); } - public final void xorps(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x57); - emitOperandHelper(dst, src); - } - protected final void decl(Register dst) { // Use two-byte form (one-byte form is a REX prefix in 64-bit mode) int encode = prefixAndEncode(dst.encoding); @@ -2281,35 +1936,15 @@ } public final void addq(Register dst, int imm32) { - emitArithImm32q(0, dst, imm32); - } - - public final void addq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x03); - emitOperandHelper(dst, src); + ADD.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); } public final void addq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x03); - emitByte(0xC0 | encode); + ADD.rmOp.emit(this, QWORD, dst, src); } public final void andq(Register dst, int imm32) { - emitArithImm32q(4, dst, imm32); - } - - public final void andq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x23); - emitOperandHelper(dst, src); - } - - public final void andq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x23); - emitByte(0xC0 | encode); + AND.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); } public final void bswapq(Register reg) { @@ -2337,27 +1972,16 @@ emitOperandHelper(dst, src); } - public final void cmpq(AMD64Address dst, int imm32) { - prefixq(dst); - emitByte(0x81); - emitOperandHelper(7, dst); - emitInt(imm32); - } - public final void cmpq(Register dst, int imm32) { - emitArithImm32q(7, dst, imm32); + CMP.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); } public final void cmpq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x3B); - emitByte(0xC0 | encode); + CMP.rmOp.emit(this, QWORD, dst, src); } public final void cmpq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x3B); - emitOperandHelper(dst, src); + CMP.rmOp.emit(this, QWORD, dst, src); } public final void cmpxchgq(Register reg, AMD64Address adr) { @@ -2367,76 +1991,6 @@ emitOperandHelper(reg, adr); } - public final void cvtsi2sdq(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - prefixq(src, dst); - emitByte(0x0F); - emitByte(0x2A); - emitOperandHelper(dst, src); - } - - public final void cvtsi2sdq(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2A); - emitByte(0xC0 | encode); - } - - public final void cvtsi2ssq(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - prefixq(src, dst); - emitByte(0x0F); - emitByte(0x2A); - emitOperandHelper(dst, src); - } - - public final void cvtsi2ssq(Register dst, Register src) { - assert dst.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2A); - emitByte(0xC0 | encode); - } - - public final void cvttsd2siq(Register dst, AMD64Address src) { - emitByte(0xF2); - prefixq(src, dst); - emitByte(0x0F); - emitByte(0x2C); - emitOperandHelper(dst, src); - } - - public final void cvttsd2siq(Register dst, Register src) { - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF2); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2C); - emitByte(0xC0 | encode); - } - - public final void cvttss2siq(Register dst, AMD64Address src) { - emitByte(0xF3); - prefixq(src, dst); - emitByte(0x0F); - emitByte(0x2C); - emitOperandHelper(dst, src); - } - - public final void cvttss2siq(Register dst, Register src) { - assert src.getRegisterCategory().equals(AMD64.XMM); - emitByte(0xF3); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x2C); - emitByte(0xC0 | encode); - } - protected final void decq(Register dst) { // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) int encode = prefixqAndEncode(dst.encoding); @@ -2444,88 +1998,6 @@ emitByte(0xC8 | encode); } - protected final void decq(AMD64Address dst) { - prefixq(dst); - emitByte(0xFF); - emitOperandHelper(1, dst); - } - - public final void divq(Register src) { - int encode = prefixqAndEncode(6, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void idivq(Register src) { - int encode = prefixqAndEncode(7, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void mulq(Register src) { - int encode = prefixqAndEncode(4, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void mulq(AMD64Address src) { - prefixq(src); - emitByte(0xF7); - emitOperandHelper(4, src); - } - - public final void imulq(Register src) { - int encode = prefixqAndEncode(5, src.encoding); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - - public final void imulq(AMD64Address src) { - prefixq(src); - emitByte(0xF7); - emitOperandHelper(5, src); - } - - public final void imulq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xAF); - emitByte(0xC0 | encode); - } - - public final void imulq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xAF); - emitOperandHelper(dst, src); - } - - public final void imulq(Register dst, Register src, int value) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - if (isByte(value)) { - emitByte(0x6B); - emitByte(0xC0 | encode); - emitByte(value & 0xFF); - } else { - emitByte(0x69); - emitByte(0xC0 | encode); - emitInt(value); - } - } - - public final void imulq(Register dst, AMD64Address src, int value) { - prefixq(src, dst); - if (isByte(value)) { - emitByte(0x6B); - emitOperandHelper(dst, src); - emitByte(value & 0xFF); - } else { - emitByte(0x69); - emitOperandHelper(dst, src); - emitInt(value); - } - } - public final void incq(Register dst) { // Don't use it directly. Use Macroincrementq() instead. // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) @@ -2602,47 +2074,6 @@ emitByte(0xD8 | encode); } - public final void notq(Register dst) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xF7); - emitByte(0xD0 | encode); - } - - public final void orq(Register dst, int imm32) { - emitArithImm32q(1, dst, imm32); - } - - public final void orq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x0B); - emitOperandHelper(dst, src); - } - - public final void orq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0B); - emitByte(0xC0 | encode); - } - - public final void sarq(Register dst, int imm8) { - assert isShiftCount(imm8 >> 1) : "illegal shift count"; - int encode = prefixqAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xF8 | encode); - } else { - emitByte(0xC1); - emitByte(0xF8 | encode); - emitByte(imm8); - } - } - - public final void sarq(Register dst) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xF8 | encode); - } - public final void shlq(Register dst, int imm8) { assert isShiftCount(imm8 >> 1) : "illegal shift count"; int encode = prefixqAndEncode(dst.encoding); @@ -2656,12 +2087,6 @@ } } - public final void shlq(Register dst) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xE0 | encode); - } - public final void shrq(Register dst, int imm8) { assert isShiftCount(imm8 >> 1) : "illegal shift count"; int encode = prefixqAndEncode(dst.encoding); @@ -2675,50 +2100,17 @@ } } - public final void shrq(Register dst) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xD3); - emitByte(0xE8 | encode); - } - public final void subq(Register dst, int imm32) { - subq(dst, imm32, false); + SUB.getMIOpcode(QWORD, isByte(imm32)).emit(this, QWORD, dst, imm32); } public final void subqWide(Register dst, int imm32) { - subq(dst, imm32, true); - } - - private void subq(Register dst, int imm32, boolean force32Imm) { - emitArithImm32q(5, dst, imm32, force32Imm); - } - - public final void subq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x2B); - emitOperandHelper(dst, src); + // don't use the sign-extending version, forcing a 32-bit immediate + SUB.getMIOpcode(QWORD, false).emit(this, QWORD, dst, imm32); } public final void subq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x2B); - emitByte(0xC0 | encode); - } - - public final void testq(Register dst, int imm32) { - // not using emitArith because test - // doesn't support sign-extension of - // 8bit operands - int encode = dst.encoding; - if (encode == 0) { - emitByte(Prefix.REXW); - emitByte(0xA9); - } else { - encode = prefixqAndEncode(encode); - emitByte(0xF7); - emitByte(0xC0 | encode); - } - emitInt(imm32); + SUB.rmOp.emit(this, QWORD, dst, src); } public final void testq(Register dst, Register src) { @@ -2727,19 +2119,6 @@ emitByte(0xC0 | encode); } - public final void testq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x85); - emitOperandHelper(dst, src); - } - - public final void testq(AMD64Address dst, int imm32) { - prefixq(dst); - emitByte(0xF7); - emitOperandHelper(0, dst); - emitInt(imm32); - } - public final void xaddl(AMD64Address dst, Register src) { prefix(dst, src); emitByte(0x0F); @@ -2766,22 +2145,6 @@ emitOperandHelper(dst, src); } - public final void xorq(Register dst, int imm32) { - emitArithImm32q(6, dst, imm32); - } - - public final void xorq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x33); - emitByte(0xC0 | encode); - } - - public final void xorq(Register dst, AMD64Address src) { - prefixq(src, dst); - emitByte(0x33); - emitOperandHelper(dst, src); - } - public final void membar(int barriers) { if (target.isMP) { // We only have to handle StoreLoad diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,10 +37,6 @@ super(target, registerConfig); } - public final void xorptr(Register dst, Register src) { - xorq(dst, src); - } - public final void decrementq(Register reg, int value) { if (value == Integer.MIN_VALUE) { subq(reg, value); @@ -175,10 +171,6 @@ } } - public final void signExtendShort(Register reg) { - movswl(reg, reg); - } - public void movflt(Register dst, Register src) { assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); if (UseXmmRegToRegMoveAll) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,12 @@ package com.oracle.graal.compiler.amd64; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64Shift.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; -import static com.oracle.graal.lir.amd64.AMD64BitManipulationOp.IntrinsicOpcode.*; -import static com.oracle.graal.lir.amd64.AMD64Compare.*; import static com.oracle.graal.lir.amd64.AMD64MathIntrinsicOp.IntrinsicOpcode.*; import com.oracle.graal.amd64.*; @@ -34,7 +37,16 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.AMD64Address.Scale; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64Shift; import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.AMD64Assembler.SSEOp; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.spi.*; @@ -42,21 +54,7 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryMemory; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStackConst; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp; import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.MulHighOp; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2MemoryOp; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2RegOp; -import com.oracle.graal.lir.amd64.AMD64Compare.CompareMemoryOp; -import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp; @@ -291,41 +289,61 @@ private void emitIntegerTest(Value a, Value b) { assert a.getKind().isNumericInteger(); - if (LIRValueUtil.isVariable(b)) { - append(new AMD64TestOp(load(b), loadNonConst(a))); + OperandSize size = a.getKind() == Kind.Long ? QWORD : DWORD; + if (isConstant(b)) { + append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(a), asConstant(b))); + } else if (isConstant(a)) { + append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(b), asConstant(a))); + } else if (isAllocatableValue(b)) { + append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a))); } else { - append(new AMD64TestOp(load(a), loadNonConst(b))); + append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b))); } } protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) { + OperandSize size; switch ((Kind) cmpKind) { case Byte: case Boolean: - append(new CompareOp(BCMP, left, right)); + size = BYTE; break; case Short: case Char: - append(new CompareOp(SCMP, left, right)); + size = WORD; break; case Int: - append(new CompareOp(ICMP, left, right)); + size = DWORD; break; case Long: - append(new CompareOp(LCMP, left, right)); - break; case Object: - append(new CompareOp(ACMP, left, right)); + size = QWORD; break; case Float: - append(new CompareOp(FCMP, left, right)); - break; + append(new AMD64CompareOp(SSEOp.UCOMIS, PS, left, asAllocatable(right))); + return; case Double: - append(new CompareOp(DCMP, left, right)); - break; + append(new AMD64CompareOp(SSEOp.UCOMIS, PD, left, asAllocatable(right))); + return; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind); } + + if (isConstant(right)) { + JavaConstant c = asConstant(right); + if (c.isDefaultForKind()) { + AMD64RMOp op = size == BYTE ? TESTB : TEST; + append(new AMD64CompareOp(op, size, left, left)); + return; + } else if (NumUtil.is32bit(c.asLong())) { + AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(c.asLong())); + append(new AMD64CompareConstOp(op, size, left, c)); + return; + } + } + + AMD64RMOp op = CMP.getRMOpcode(size); + append(new AMD64CompareOp(op, size, left, asAllocatable(right))); } /** @@ -336,74 +354,54 @@ * @return true if the left and right operands were switched, false otherwise */ private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) { - boolean mirrored; - if (LIRValueUtil.isVariable(a)) { - Variable left = load(a); - emitCompareRegMemoryOp(cmpKind, left, b, state); - mirrored = false; - } else { - emitCompareMemoryConOp(cmpKind, b, (JavaConstant) a, state); - mirrored = true; - } - return mirrored; - } - - protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { - assert kind.getStackKind() == value.getKind().getStackKind(); - switch (kind) { + OperandSize size; + switch (cmpKind) { case Byte: case Boolean: - append(new CompareMemoryOp(BCMP, kind, address, value, state)); + size = BYTE; break; case Short: case Char: - append(new CompareMemoryOp(SCMP, kind, address, value, state)); + size = WORD; break; case Int: - append(new CompareMemoryOp(ICMP, kind, address, value, state)); + size = DWORD; break; case Long: - append(new CompareMemoryOp(LCMP, kind, address, value, state)); + case Object: + size = QWORD; break; - case Object: - assert value.isNull(); - append(new CompareMemoryOp(ACMP, kind, address, value, state)); - break; + case Float: + append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state)); + return false; + case Double: + append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state)); + return false; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind); + } + + if (isConstant(a)) { + return emitCompareMemoryConOp(size, asConstant(a), b, state); + } else { + return emitCompareRegMemoryOp(size, a, b, state); } } - protected void emitCompareRegMemoryOp(Kind kind, Value value, AMD64AddressValue address, LIRFrameState state) { - AMD64Compare opcode = null; - switch (kind) { - case Byte: - case Boolean: - opcode = BCMP; - break; - case Short: - case Char: - opcode = SCMP; - break; - case Int: - opcode = ICMP; - break; - case Long: - opcode = LCMP; - break; - case Object: - opcode = ACMP; - break; - case Float: - opcode = FCMP; - break; - case Double: - opcode = DCMP; - break; - default: - throw GraalInternalError.shouldNotReachHere(); + protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) { + if (NumUtil.is32bit(a.asLong())) { + AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(a.asLong())); + append(new AMD64CompareMemoryConstOp(op, size, b, a, state)); + return true; + } else { + return emitCompareRegMemoryOp(size, a, b, state); } - append(new CompareMemoryOp(opcode, kind, address, value, state)); + } + + private boolean emitCompareRegMemoryOp(OperandSize size, Value a, AMD64AddressValue b, LIRFrameState state) { + AMD64RMOp op = CMP.getRMOpcode(size); + append(new AMD64CompareMemoryOp(op, size, asAllocatable(a), b, state)); + return false; } /** @@ -437,16 +435,16 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind()) { case Int: - append(new Unary1Op(INEG, result, input)); + append(new AMD64UnaryMOp(NEG, DWORD, result, input)); break; case Long: - append(new Unary1Op(LNEG, result, input)); + append(new AMD64UnaryMOp(NEG, QWORD, result, input)); break; case Float: - append(new BinaryRegConst(FXOR, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)))); + append(new AMD64BinaryPatchOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16)); break; case Double: - append(new BinaryRegConst(DXOR, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)))); + append(new AMD64BinaryPatchOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -460,10 +458,10 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind()) { case Int: - append(new Unary1Op(INOT, result, input)); + append(new AMD64UnaryMOp(NOT, DWORD, result, input)); break; case Long: - append(new Unary1Op(LNOT, result, input)); + append(new AMD64UnaryMOp(NOT, QWORD, result, input)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -471,54 +469,48 @@ return result; } - private Variable emitBinary(AMD64Arithmetic op, boolean commutative, Value a, Value b) { + private Variable emitBinary(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b) { if (isConstant(b)) { - return emitBinaryConst(op, commutative, asAllocatable(a), asConstant(b)); + return emitBinaryConst(op, size, commutative, asAllocatable(a), asConstant(b)); } else if (commutative && isConstant(a)) { - return emitBinaryConst(op, commutative, asAllocatable(b), asConstant(a)); + return emitBinaryConst(op, size, commutative, asAllocatable(b), asConstant(a)); } else { - return emitBinaryVar(op, commutative, asAllocatable(a), asAllocatable(b)); + return emitBinaryVar(op.getRMOpcode(size), size, commutative, asAllocatable(a), asAllocatable(b)); + } + } + + private Variable emitBinary(AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) { + if (isConstant(b)) { + return emitBinaryConst(op, size, asAllocatable(a), asConstant(b)); + } else if (commutative && isConstant(a)) { + return emitBinaryConst(op, size, asAllocatable(b), asConstant(a)); + } else { + return emitBinaryVar(op, size, commutative, asAllocatable(a), asAllocatable(b)); } } - private Variable emitBinaryConst(AMD64Arithmetic op, boolean commutative, AllocatableValue a, JavaConstant b) { - switch (op) { - case IADD: - case LADD: - case ISUB: - case LSUB: - case IAND: - case LAND: - case IOR: - case LOR: - case IXOR: - case LXOR: - if (NumUtil.isInt(b.asLong())) { - Variable result = newVariable(LIRKind.derive(a, b)); - append(new BinaryRegConst(op, result, a, b)); - return result; - } - break; - - case IMUL: - case LMUL: - if (NumUtil.isInt(b.asLong())) { - Variable result = newVariable(LIRKind.derive(a, b)); - append(new BinaryRegStackConst(op, result, a, b)); - return result; - } - break; + private Variable emitBinaryConst(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, JavaConstant b) { + if (NumUtil.isInt(b.asLong())) { + Variable result = newVariable(LIRKind.derive(a, b)); + append(new AMD64BinaryConstOp(op, size, result, a, b)); + return result; + } else { + return emitBinaryVar(op.getRMOpcode(size), size, commutative, a, asAllocatable(b)); } - - return emitBinaryVar(op, commutative, a, asAllocatable(b)); } - private Variable emitBinaryVar(AMD64Arithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b) { + private Variable emitBinaryConst(AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) { + Variable result = newVariable(LIRKind.derive(a, b)); + append(new AMD64BinaryPatchOp(op, size, result, a, b)); + return result; + } + + private Variable emitBinaryVar(AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) { Variable result = newVariable(LIRKind.derive(a, b)); if (commutative) { - append(new BinaryCommutative(op, result, a, b)); + append(new AMD64BinaryCommutativeOp(op, size, result, a, b)); } else { - append(new BinaryRegStack(op, result, a, b)); + append(new AMD64BinaryOp(op, size, result, a, b)); } return result; } @@ -527,13 +519,13 @@ public Variable emitAdd(Value a, Value b, boolean setFlags) { switch (a.getKind().getStackKind()) { case Int: - return emitBinary(IADD, true, a, b); + return emitBinary(ADD, DWORD, true, a, b); case Long: - return emitBinary(LADD, true, a, b); + return emitBinary(ADD, QWORD, true, a, b); case Float: - return emitBinary(FADD, true, a, b); + return emitBinary(SSEOp.ADD, SS, true, a, b); case Double: - return emitBinary(DADD, true, a, b); + return emitBinary(SSEOp.ADD, SD, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -543,48 +535,80 @@ public Variable emitSub(Value a, Value b, boolean setFlags) { switch (a.getKind().getStackKind()) { case Int: - return emitBinary(ISUB, false, a, b); + return emitBinary(SUB, DWORD, false, a, b); case Long: - return emitBinary(LSUB, false, a, b); + return emitBinary(SUB, QWORD, false, a, b); case Float: - return emitBinary(FSUB, false, a, b); + return emitBinary(SSEOp.SUB, SS, false, a, b); case Double: - return emitBinary(DSUB, false, a, b); + return emitBinary(SSEOp.SUB, SD, false, a, b); default: throw GraalInternalError.shouldNotReachHere(); } } + private Variable emitIMULConst(OperandSize size, AllocatableValue a, JavaConstant b) { + if (NumUtil.isInt(b.asLong())) { + int imm = (int) b.asLong(); + AMD64RMIOp op; + if (NumUtil.isByte(imm)) { + op = AMD64RMIOp.IMUL_SX; + } else { + op = AMD64RMIOp.IMUL; + } + + Variable ret = newVariable(LIRKind.derive(a, b)); + append(new AMD64MulConstOp(op, size, ret, a, b)); + return ret; + } else { + return emitBinaryVar(AMD64RMOp.IMUL, size, true, a, asAllocatable(b)); + } + } + + private Variable emitIMUL(OperandSize size, Value a, Value b) { + if (isConstant(b)) { + return emitIMULConst(size, asAllocatable(a), asConstant(b)); + } else if (isConstant(a)) { + return emitIMULConst(size, asAllocatable(b), asConstant(a)); + } else { + return emitBinaryVar(AMD64RMOp.IMUL, size, true, asAllocatable(a), asAllocatable(b)); + } + } + @Override public Variable emitMul(Value a, Value b, boolean setFlags) { switch (a.getKind().getStackKind()) { case Int: - return emitBinary(IMUL, true, a, b); + return emitIMUL(DWORD, a, b); case Long: - return emitBinary(LMUL, true, a, b); + return emitIMUL(QWORD, a, b); case Float: - return emitBinary(FMUL, true, a, b); + return emitBinary(SSEOp.MUL, SS, true, a, b); case Double: - return emitBinary(DMUL, true, a, b); + return emitBinary(SSEOp.MUL, SD, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } } - private Value emitMulHigh(AMD64Arithmetic opcode, Value a, Value b) { - MulHighOp mulHigh = new MulHighOp(opcode, LIRKind.derive(a, b), asAllocatable(b)); - emitMove(mulHigh.x, a); - append(mulHigh); - return emitMove(mulHigh.highResult); + private RegisterValue moveToReg(Register reg, Value v) { + RegisterValue ret = reg.asValue(v.getLIRKind()); + emitMove(ret, v); + return ret; + } + + private Value emitMulHigh(AMD64MOp opcode, OperandSize size, Value a, Value b) { + AMD64MulDivOp mulHigh = append(new AMD64MulDivOp(opcode, size, LIRKind.derive(a, b), moveToReg(AMD64.rax, a), asAllocatable(b))); + return emitMove(mulHigh.getHighResult()); } @Override public Value emitMulHigh(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitMulHigh(IMUL, a, b); + return emitMulHigh(AMD64MOp.IMUL, DWORD, a, b); case Long: - return emitMulHigh(LMUL, a, b); + return emitMulHigh(AMD64MOp.IMUL, QWORD, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -594,23 +618,23 @@ public Value emitUMulHigh(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitMulHigh(IUMUL, a, b); + return emitMulHigh(AMD64MOp.MUL, DWORD, a, b); case Long: - return emitMulHigh(LUMUL, a, b); + return emitMulHigh(AMD64MOp.MUL, QWORD, a, b); default: throw GraalInternalError.shouldNotReachHere(); } } - public Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { + public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { Variable result = newVariable(LIRKind.derive(a)); - append(new BinaryMemory(op, kind, result, a, location, state)); + append(new AMD64BinaryMemoryOp(op, size, result, a, location, state)); return result; } - protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, AMD64AddressValue address, LIRFrameState state) { + protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) { Variable result = newVariable(LIRKind.value(kind)); - append(new Unary2MemoryOp(op, result, (Kind) null, address, state)); + append(new AMD64UnaryMemoryOp(op, size, result, address, state)); return result; } @@ -622,48 +646,50 @@ return result; } - private DivRemOp emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) { - AllocatableValue rax = AMD64.rax.asValue(a.getLIRKind()); - emitMove(rax, a); - DivRemOp ret = new DivRemOp(op, rax, asAllocatable(b), state); - append(ret); - return ret; + private AMD64MulDivOp emitIDIV(OperandSize size, Value a, Value b, LIRFrameState state) { + LIRKind kind = LIRKind.derive(a, b); + + AMD64SignExtendOp sx = append(new AMD64SignExtendOp(size, kind, moveToReg(AMD64.rax, a))); + return append(new AMD64MulDivOp(AMD64MOp.IDIV, size, kind, sx.getHighResult(), sx.getLowResult(), asAllocatable(b), state)); + } + + private AMD64MulDivOp emitDIV(OperandSize size, Value a, Value b, LIRFrameState state) { + LIRKind kind = LIRKind.derive(a, b); + + RegisterValue rax = moveToReg(AMD64.rax, a); + RegisterValue rdx = AMD64.rdx.asValue(kind); + append(new AMD64ClearRegisterOp(size, rdx)); + return append(new AMD64MulDivOp(AMD64MOp.DIV, size, kind, rdx, rax, asAllocatable(b), state)); } public Value[] emitIntegerDivRem(Value a, Value b, LIRFrameState state) { - DivRemOp op; + AMD64MulDivOp op; switch (a.getKind().getStackKind()) { case Int: - op = emitDivRem(IDIVREM, a, b, state); + op = emitIDIV(DWORD, a, b, state); break; case Long: - op = emitDivRem(LDIVREM, a, b, state); + op = emitIDIV(QWORD, a, b, state); break; default: throw GraalInternalError.shouldNotReachHere(); } - return new Value[]{emitMove(op.divResult), emitMove(op.remResult)}; + return new Value[]{emitMove(op.getQuotient()), emitMove(op.getRemainder())}; } @Override public Value emitDiv(Value a, Value b, LIRFrameState state) { switch (a.getKind().getStackKind()) { case Int: - DivRemOp op = emitDivRem(IDIV, a, b, state); - return emitMove(op.divResult); + AMD64MulDivOp op = emitIDIV(DWORD, a, b, state); + return emitMove(op.getQuotient()); case Long: - DivRemOp lop = emitDivRem(LDIV, a, b, state); - return emitMove(lop.divResult); - case Float: { - Variable result = newVariable(LIRKind.derive(a, b)); - append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b))); - return result; - } - case Double: { - Variable result = newVariable(LIRKind.derive(a, b)); - append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b))); - return result; - } + AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state); + return emitMove(lop.getQuotient()); + case Float: + return emitBinary(SSEOp.DIV, SS, false, a, b); + case Double: + return emitBinary(SSEOp.DIV, SD, false, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -673,11 +699,11 @@ public Value emitRem(Value a, Value b, LIRFrameState state) { switch (a.getKind().getStackKind()) { case Int: - DivRemOp op = emitDivRem(IREM, a, b, state); - return emitMove(op.remResult); + AMD64MulDivOp op = emitIDIV(DWORD, a, b, state); + return emitMove(op.getRemainder()); case Long: - DivRemOp lop = emitDivRem(LREM, a, b, state); - return emitMove(lop.remResult); + AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state); + return emitMove(lop.getRemainder()); case Float: { Variable result = newVariable(LIRKind.derive(a, b)); append(new FPDivRemOp(FREM, result, load(a), load(b))); @@ -695,43 +721,47 @@ @Override public Variable emitUDiv(Value a, Value b, LIRFrameState state) { - DivRemOp op; + AMD64MulDivOp op; switch (a.getKind().getStackKind()) { case Int: - op = emitDivRem(IUDIV, a, b, state); + op = emitDIV(DWORD, a, b, state); break; case Long: - op = emitDivRem(LUDIV, a, b, state); + op = emitDIV(QWORD, a, b, state); break; default: throw GraalInternalError.shouldNotReachHere(); } - return emitMove(op.divResult); + return emitMove(op.getQuotient()); } @Override public Variable emitURem(Value a, Value b, LIRFrameState state) { - DivRemOp op; + AMD64MulDivOp op; switch (a.getKind().getStackKind()) { case Int: - op = emitDivRem(IUREM, a, b, state); + op = emitDIV(DWORD, a, b, state); break; case Long: - op = emitDivRem(LUREM, a, b, state); + op = emitDIV(QWORD, a, b, state); break; default: throw GraalInternalError.shouldNotReachHere(); } - return emitMove(op.remResult); + return emitMove(op.getRemainder()); } @Override public Variable emitAnd(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitBinary(IAND, true, a, b); + return emitBinary(AND, DWORD, true, a, b); case Long: - return emitBinary(LAND, true, a, b); + return emitBinary(AND, QWORD, true, a, b); + case Float: + return emitBinary(SSEOp.AND, PS, true, a, b); + case Double: + return emitBinary(SSEOp.AND, PD, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -741,9 +771,13 @@ public Variable emitOr(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitBinary(IOR, true, a, b); + return emitBinary(OR, DWORD, true, a, b); case Long: - return emitBinary(LOR, true, a, b); + return emitBinary(OR, QWORD, true, a, b); + case Float: + return emitBinary(SSEOp.OR, PS, true, a, b); + case Double: + return emitBinary(SSEOp.OR, PD, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -753,22 +787,31 @@ public Variable emitXor(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitBinary(IXOR, true, a, b); + return emitBinary(XOR, DWORD, true, a, b); case Long: - return emitBinary(LXOR, true, a, b); + return emitBinary(XOR, QWORD, true, a, b); + case Float: + return emitBinary(SSEOp.XOR, PS, true, a, b); + case Double: + return emitBinary(SSEOp.XOR, PD, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } } - private Variable emitShift(AMD64Arithmetic op, Value a, Value b) { + private Variable emitShift(AMD64Shift op, OperandSize size, Value a, Value b) { Variable result = newVariable(LIRKind.derive(a, b).changeType(a.getPlatformKind())); AllocatableValue input = asAllocatable(a); if (isConstant(b)) { - append(new BinaryRegConst(op, result, input, asConstant(b))); + JavaConstant c = asConstant(b); + if (c.asLong() == 1) { + append(new AMD64UnaryMOp(op.m1Op, size, result, input)); + } else { + append(new AMD64BinaryConstOp(op.miOp, size, result, input, c)); + } } else { emitMove(RCX_I, b); - append(new BinaryRegReg(op, result, input, RCX_I)); + append(new AMD64ShiftOp(op.mcOp, size, result, input, RCX_I)); } return result; } @@ -777,9 +820,9 @@ public Variable emitShl(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitShift(ISHL, a, b); + return emitShift(SHL, DWORD, a, b); case Long: - return emitShift(LSHL, a, b); + return emitShift(SHL, QWORD, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -789,9 +832,9 @@ public Variable emitShr(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitShift(ISHR, a, b); + return emitShift(SAR, DWORD, a, b); case Long: - return emitShift(LSHR, a, b); + return emitShift(SAR, QWORD, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -801,9 +844,9 @@ public Variable emitUShr(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitShift(IUSHR, a, b); + return emitShift(SHR, DWORD, a, b); case Long: - return emitShift(LUSHR, a, b); + return emitShift(SHR, QWORD, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -812,9 +855,9 @@ public Variable emitRol(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitShift(IROL, a, b); + return emitShift(ROL, DWORD, a, b); case Long: - return emitShift(LROL, a, b); + return emitShift(ROL, QWORD, a, b); default: throw GraalInternalError.shouldNotReachHere(); } @@ -823,23 +866,23 @@ public Variable emitRor(Value a, Value b) { switch (a.getKind().getStackKind()) { case Int: - return emitShift(IROR, a, b); + return emitShift(ROR, DWORD, a, b); case Long: - return emitShift(LROR, a, b); + return emitShift(ROR, QWORD, a, b); default: throw GraalInternalError.shouldNotReachHere(); } } - private AllocatableValue emitConvert2RegOp(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) { + private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) { Variable result = newVariable(kind); - append(new Unary2RegOp(op, result, input)); + append(new AMD64UnaryRMOp(op, size, result, asAllocatable(input))); return result; } - private AllocatableValue emitConvert2Op(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) { + private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) { Variable result = newVariable(kind); - append(new Unary2Op(op, result, input)); + append(new AMD64UnaryMROp(op, size, result, asAllocatable(input))); return result; } @@ -860,54 +903,53 @@ case Int: switch (fromKind) { case Float: - return emitConvert2Op(to, MOV_F2I, input); + return emitConvertOp(to, AMD64MROp.MOVD, DWORD, input); } break; case Long: switch (fromKind) { case Double: - return emitConvert2Op(to, MOV_D2L, input); + return emitConvertOp(to, AMD64MROp.MOVQ, QWORD, input); } break; case Float: switch (fromKind) { case Int: - return emitConvert2Op(to, MOV_I2F, input); + return emitConvertOp(to, AMD64RMOp.MOVD, DWORD, input); } break; case Double: switch (fromKind) { case Long: - return emitConvert2Op(to, MOV_L2D, input); + return emitConvertOp(to, AMD64RMOp.MOVQ, QWORD, input); } break; } throw GraalInternalError.shouldNotReachHere(); } - public Value emitFloatConvert(FloatConvert op, Value inputVal) { - AllocatableValue input = asAllocatable(inputVal); + public Value emitFloatConvert(FloatConvert op, Value input) { switch (op) { case D2F: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), D2F, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSD2SS, SD, input); case D2I: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), D2I, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Int), SSEOp.CVTTSD2SI, DWORD, input); case D2L: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), D2L, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Long), SSEOp.CVTTSD2SI, QWORD, input); case F2D: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), F2D, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSS2SD, SS, input); case F2I: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), F2I, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Int), SSEOp.CVTTSS2SI, DWORD, input); case F2L: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), F2L, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Long), SSEOp.CVTTSS2SI, QWORD, input); case I2D: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), I2D, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSI2SD, DWORD, input); case I2F: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), I2F, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSI2SS, DWORD, input); case L2D: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), L2D, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Double), SSEOp.CVTSI2SD, QWORD, input); case L2F: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), L2F, input); + return emitConvertOp(LIRKind.derive(input).changeType(Kind.Float), SSEOp.CVTSI2SS, QWORD, input); default: throw GraalInternalError.shouldNotReachHere(); } @@ -917,7 +959,7 @@ public Value emitNarrow(Value inputVal, int bits) { if (inputVal.getKind() == Kind.Long && bits <= 32) { // TODO make it possible to reinterpret Long as Int in LIR without move - return emitConvert2RegOp(LIRKind.derive(inputVal).changeType(Kind.Int), L2I, asAllocatable(inputVal)); + return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), AMD64RMOp.MOV, DWORD, inputVal); } else { return inputVal; } @@ -932,11 +974,11 @@ // sign extend to 64 bits switch (fromBits) { case 8: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), B2L, asAllocatable(inputVal)); + return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSXB, QWORD, inputVal); case 16: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), S2L, asAllocatable(inputVal)); + return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSX, QWORD, inputVal); case 32: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), I2L, asAllocatable(inputVal)); + return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Long), MOVSXD, QWORD, inputVal); default: throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); } @@ -944,9 +986,9 @@ // sign extend to 32 bits (smaller values are internally represented as 32 bit values) switch (fromBits) { case 8: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), B2I, asAllocatable(inputVal)); + return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), MOVSXB, DWORD, inputVal); case 16: - return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), S2I, asAllocatable(inputVal)); + return emitConvertOp(LIRKind.derive(inputVal).changeType(Kind.Int), MOVSX, DWORD, inputVal); case 32: return inputVal; default: @@ -964,13 +1006,13 @@ assert inputVal.getKind() == Kind.Long; Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); long mask = CodeUtil.mask(fromBits); - append(new BinaryRegConst(AMD64Arithmetic.LAND, result, asAllocatable(inputVal), JavaConstant.forLong(mask))); + append(new AMD64BinaryPatchOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask))); return result; } else { assert inputVal.getKind().getStackKind() == Kind.Int; Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int)); int mask = (int) CodeUtil.mask(fromBits); - append(new BinaryRegConst(AMD64Arithmetic.IAND, result, asAllocatable(inputVal), JavaConstant.forInt(mask))); + append(new AMD64BinaryPatchOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask))); if (toBits > 32) { Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); emitMove(longResult, result); @@ -1005,9 +1047,9 @@ public Variable emitBitCount(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(POPCNT, DWORD, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LPOPCNT, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(POPCNT, QWORD, result, asAllocatable(value))); } return result; } @@ -1015,7 +1057,7 @@ @Override public Variable emitBitScanForward(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); - append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(BSF, QWORD, result, asAllocatable(value))); return result; } @@ -1023,9 +1065,9 @@ public Variable emitBitScanReverse(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(BSR, DWORD, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LBSR, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(BSR, QWORD, result, asAllocatable(value))); } return result; } @@ -1033,9 +1075,9 @@ public Value emitCountLeadingZeros(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(ILZCNT, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(LZCNT, DWORD, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LLZCNT, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(LZCNT, QWORD, result, asAllocatable(value))); } return result; } @@ -1043,9 +1085,9 @@ public Value emitCountTrailingZeros(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(ITZCNT, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(TZCNT, DWORD, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LTZCNT, result, asAllocatable(value))); + append(new AMD64UnaryRMOp(TZCNT, QWORD, result, asAllocatable(value))); } return result; } @@ -1055,10 +1097,10 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind()) { case Float: - append(new BinaryRegConst(FAND, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)))); + append(new AMD64BinaryPatchOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16)); break; case Double: - append(new BinaryRegConst(DAND, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)))); + append(new AMD64BinaryPatchOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -1069,7 +1111,16 @@ @Override public Value emitMathSqrt(Value input) { Variable result = newVariable(LIRKind.derive(input)); - append(new Unary2Op(SQRT, result, asAllocatable(input))); + switch (input.getKind()) { + case Float: + append(new AMD64UnaryRMOp(SSEOp.SQRT, SS, result, asAllocatable(input))); + break; + case Double: + append(new AMD64UnaryRMOp(SSEOp.SQRT, SD, result, asAllocatable(input))); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } return result; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,18 @@ package com.oracle.graal.compiler.amd64; -import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.AMD64Assembler.SSEOp; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.gen.*; @@ -108,6 +114,27 @@ return (Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind(); } + protected OperandSize getMemorySize(Access access) { + switch (getMemoryKind(access)) { + case Boolean: + case Byte: + return OperandSize.BYTE; + case Char: + case Short: + return OperandSize.WORD; + case Int: + return OperandSize.DWORD; + case Long: + return OperandSize.QWORD; + case Float: + return OperandSize.SS; + case Double: + return OperandSize.SD; + default: + throw GraalInternalError.shouldNotReachHere("unsupported memory access type " + getMemoryKind(access)); + } + } + protected AMD64AddressValue makeAddress(Access access) { return (AMD64AddressValue) access.accessLocation().generateAddress(this, gen, operand(access.object())); } @@ -176,6 +203,7 @@ LabelRef falseLabel = getLIRBlock(x.falseSuccessor()); double trueLabelProbability = x.probability(x.trueSuccessor()); Kind kind = getMemoryKind(access); + OperandSize size = kind == Kind.Long ? QWORD : DWORD; if (value.isConstant()) { if (kind != kind.getStackKind()) { return null; @@ -186,83 +214,61 @@ return null; } return builder -> { - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access))); + gen.append(new AMD64CompareMemoryConstOp(AMD64MIOp.TEST, size, makeAddress(access), constant, getState(access))); gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); return null; }; } else { return builder -> { - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access))); + gen.append(new AMD64CompareMemoryOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), makeAddress(access), getState(access))); gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); return null; }; } } - protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) { - AMD64AddressValue address = makeAddress(access); - LIRFrameState state = getState(access); - return getLIRGeneratorTool().emitConvert2MemoryOp(kind, op, address, state); - } - - private Value emitFloatConvertMemory(FloatConvertNode op, Access access) { - switch (op.getFloatConvert()) { - case D2F: - return emitConvert2MemoryOp(Kind.Float, D2F, access); - case D2I: - return emitConvert2MemoryOp(Kind.Int, D2I, access); - case D2L: - return emitConvert2MemoryOp(Kind.Long, D2L, access); - case F2D: - return emitConvert2MemoryOp(Kind.Double, F2D, access); - case F2I: - return emitConvert2MemoryOp(Kind.Int, F2I, access); - case F2L: - return emitConvert2MemoryOp(Kind.Long, F2L, access); - case I2D: - return emitConvert2MemoryOp(Kind.Double, I2D, access); - case I2F: - return emitConvert2MemoryOp(Kind.Float, I2F, access); - case L2D: - return emitConvert2MemoryOp(Kind.Double, L2D, access); - case L2F: - return emitConvert2MemoryOp(Kind.Float, L2F, access); - default: - throw GraalInternalError.shouldNotReachHere(); - } + protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) { + return builder -> { + AMD64AddressValue address = makeAddress(access); + LIRFrameState state = getState(access); + return getLIRGeneratorTool().emitConvertMemoryOp(kind, op, size, address, state); + }; } private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) { assert fromBits <= toBits && toBits <= 64; Kind kind = null; - AMD64Arithmetic op = null; + AMD64RMOp op; + OperandSize size; if (fromBits == toBits) { return null; } else if (toBits > 32) { kind = Kind.Long; + size = QWORD; // sign extend to 64 bits switch (fromBits) { case 8: - op = B2L; + op = MOVSXB; break; case 16: - op = S2L; + op = MOVSX; break; case 32: - op = I2L; + op = MOVSXD; break; default: throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); } } else { kind = Kind.Int; + size = DWORD; // sign extend to 32 bits (smaller values are internally represented as 32 bit values) switch (fromBits) { case 8: - op = B2I; + op = MOVSXB; break; case 16: - op = S2I; + op = MOVSX; break; case 32: return null; @@ -271,13 +277,7 @@ } } if (kind != null && op != null) { - Kind localKind = kind; - AMD64Arithmetic localOp = op; - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - return emitConvert2MemoryOp(localKind, localOp, access); - } - }; + return emitConvertMemoryOp(kind, op, size, access); } return null; } @@ -288,66 +288,6 @@ return getLIRGeneratorTool().emitLoad(to, address, state); } - protected AMD64Arithmetic getOp(ValueNode operation, Access access) { - Kind memoryKind = getMemoryKind(access); - if (operation.getClass() == AddNode.class) { - switch (memoryKind) { - case Int: - return IADD; - case Long: - return LADD; - case Float: - return FADD; - case Double: - return DADD; - } - } else if (operation.getClass() == AndNode.class) { - switch (memoryKind) { - case Int: - return IAND; - case Long: - return LAND; - } - } else if (operation.getClass() == OrNode.class) { - switch (memoryKind) { - case Int: - return IOR; - case Long: - return LOR; - } - } else if (operation.getClass() == XorNode.class) { - switch (memoryKind) { - case Int: - return IXOR; - case Long: - return LXOR; - } - } else if (operation.getClass() == SubNode.class) { - switch (memoryKind) { - case Int: - return ISUB; - case Long: - return LSUB; - case Float: - return FSUB; - case Double: - return DSUB; - } - } else if (operation.getClass() == MulNode.class) { - switch (memoryKind) { - case Int: - return IMUL; - case Long: - return LMUL; - case Float: - return FMUL; - case Double: - return DMUL; - } - } - return null; - } - @MatchRule("(If (IntegerTest Read=access value))") @MatchRule("(If (IntegerTest FloatingRead=access value))") public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) { @@ -392,24 +332,74 @@ return null; } + private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) { + return builder -> getLIRGeneratorTool().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access)); + } + @MatchRule("(Add value Read=access)") + @MatchRule("(Add value FloatingRead=access)") + public ComplexMatchResult addMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return binaryRead(SSEOp.ADD, size, value, access); + } else { + return binaryRead(ADD.getRMOpcode(size), size, value, access); + } + } + @MatchRule("(Sub value Read=access)") + @MatchRule("(Sub value FloatingRead=access)") + public ComplexMatchResult subMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return binaryRead(SSEOp.SUB, size, value, access); + } else { + return binaryRead(SUB.getRMOpcode(size), size, value, access); + } + } + @MatchRule("(Mul value Read=access)") - @MatchRule("(Or value Read=access)") - @MatchRule("(Xor value Read=access)") - @MatchRule("(And value Read=access)") - @MatchRule("(Add value FloatingRead=access)") - @MatchRule("(Sub value FloatingRead=access)") @MatchRule("(Mul value FloatingRead=access)") - @MatchRule("(Or value FloatingRead=access)") - @MatchRule("(Xor value FloatingRead=access)") + public ComplexMatchResult mulMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return binaryRead(SSEOp.MUL, size, value, access); + } else { + return binaryRead(AMD64RMOp.IMUL, size, value, access); + } + } + + @MatchRule("(And value Read=access)") @MatchRule("(And value FloatingRead=access)") - public ComplexMatchResult binaryRead(BinaryNode root, ValueNode value, Access access) { - AMD64Arithmetic op = getOp(root, access); - if (op != null) { - return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access)); + public ComplexMatchResult andMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryRead(AND.getRMOpcode(size), size, value, access); } - return null; + } + + @MatchRule("(Or value Read=access)") + @MatchRule("(Or value FloatingRead=access)") + public ComplexMatchResult orMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryRead(OR.getRMOpcode(size), size, value, access); + } + } + + @MatchRule("(Xor value Read=access)") + @MatchRule("(Xor value FloatingRead=access)") + public ComplexMatchResult xorMemory(ValueNode value, Access access) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryRead(XOR.getRMOpcode(size), size, value, access); + } } @MatchRule("(Write Narrow=narrow location value)") @@ -447,8 +437,30 @@ @MatchRule("(FloatConvert Read=access)") @MatchRule("(FloatConvert FloatingRead=access)") public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) { - return builder -> emitFloatConvertMemory(root, access); - + switch (root.getFloatConvert()) { + case D2F: + return emitConvertMemoryOp(Kind.Float, SSEOp.CVTSD2SS, SD, access); + case D2I: + return emitConvertMemoryOp(Kind.Int, SSEOp.CVTTSD2SI, DWORD, access); + case D2L: + return emitConvertMemoryOp(Kind.Long, SSEOp.CVTTSD2SI, QWORD, access); + case F2D: + return emitConvertMemoryOp(Kind.Double, SSEOp.CVTSS2SD, SS, access); + case F2I: + return emitConvertMemoryOp(Kind.Int, SSEOp.CVTTSS2SI, DWORD, access); + case F2L: + return emitConvertMemoryOp(Kind.Long, SSEOp.CVTTSS2SI, QWORD, access); + case I2D: + return emitConvertMemoryOp(Kind.Double, SSEOp.CVTSI2SD, DWORD, access); + case I2F: + return emitConvertMemoryOp(Kind.Float, SSEOp.CVTSI2SS, DWORD, access); + case L2D: + return emitConvertMemoryOp(Kind.Double, SSEOp.CVTSI2SD, QWORD, access); + case L2F: + return emitConvertMemoryOp(Kind.Float, SSEOp.CVTSI2SS, QWORD, access); + default: + throw GraalInternalError.shouldNotReachHere(); + } } @MatchRule("(Reinterpret Read=access)") diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java Tue Mar 17 12:05:51 2015 +0100 @@ -89,6 +89,14 @@ } /** + * True if block {@code a} dominates block {@code b} and {@code a} is not identical block to + * {@code b}. + */ + static boolean strictlyDominates(AbstractBlockBase a, AbstractBlockBase b) { + return a != b && dominates(a, b); + } + + /** * True if block {@code a} dominates block {@code b}. */ static boolean dominates(AbstractBlockBase a, AbstractBlockBase b) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -305,7 +305,6 @@ protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); - schedule.setScheduleConstants(true); schedule.apply(graph); NodeMap canonicalId = graph.createNodeMap(); @@ -325,7 +324,7 @@ } result.append("\n"); for (Node node : schedule.getBlockToNodesMap().get(block)) { - if (node.isAlive()) { + if (node instanceof ValueNode && node.isAlive()) { if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) { if (node instanceof ConstantNode) { String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -45,7 +45,7 @@ Block aBlock = nodeToBlock.get(a); if (bBlock == aBlock) { - List instructions = ibp.nodesFor(bBlock); + List instructions = ibp.nodesFor(bBlock); Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a)); } else { Block block = bBlock; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -23,10 +23,12 @@ package com.oracle.graal.compiler.test; import static com.oracle.graal.compiler.common.GraalOptions.*; + import java.util.*; import org.junit.*; +import com.oracle.graal.api.directives.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; @@ -251,6 +253,62 @@ } /** + * Here the read should not float out of the loop. + */ + public static int testLoop6Snippet(int a, int b, MemoryScheduleTest obj) { + int ret = 0; + int bb = b; + for (int i = 0; i < a; i++) { + ret = obj.hash; + if (a > 10) { + bb++; + } else { + bb--; + for (int j = 0; j < b; ++j) { + obj.hash = 3; + } + } + ret = ret / 10; + } + return ret + bb; + } + + @Test + public void testLoop6() { + SchedulePhase schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(13, schedule.getCFG().getBlocks().size()); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** + * Here the read should not float to the end. + */ + public static int testLoop7Snippet(int a, int b) { + int result = container.a; + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + break; + } else { + for (int j = 0; j < b; j++) { + container.a = 0; + } + } + } + GraalDirectives.controlFlowAnchor(); + return result; + } + + @Test + public void testLoop7() { + SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(10, schedule.getCFG().getBlocks().size()); + assertReadWithinStartBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** * Here the read should float to the end (into the same block as the return). */ public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -60,10 +60,10 @@ NodeMap nodeToBlock = schedule.getCFG().getNodeToBlock(); assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1); LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first(); - List list = schedule.nodesFor(nodeToBlock.get(loopExit)); + List list = schedule.nodesFor(nodeToBlock.get(loopExit)); for (BinaryArithmeticNode node : graph.getNodes().filter(BinaryArithmeticNode.class)) { if (!(node instanceof AddNode)) { - assertTrue(nodeToBlock.get(node) == nodeToBlock.get(loopExit)); + assertTrue(node.toString(), nodeToBlock.get(node) == nodeToBlock.get(loopExit)); assertTrue(list.indexOf(node) + " < " + list.indexOf(loopExit) + ", " + node + ", " + loopExit, list.indexOf(node) < list.indexOf(loopExit)); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Mar 17 12:05:51 2015 +0100 @@ -269,7 +269,6 @@ graph.maybeCompress(); SchedulePhase schedule = new SchedulePhase(); - schedule.setScheduleConstants(true); schedule.apply(graph); Debug.dump(schedule, "Final HIR schedule"); return schedule; @@ -284,7 +283,6 @@ // Repeatedly run the LIR code generation pass to improve statistical profiling results. for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) { SchedulePhase dummySchedule = new SchedulePhase(); - dummySchedule.setScheduleConstants(true); dummySchedule.apply(graph); emitLIR(backend, target, dummySchedule, graph, stub, cc, registerConfig, lirSuites); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -26,6 +26,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.graph.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.phases.*; import com.oracle.graal.nodes.*; @@ -61,7 +62,7 @@ context.lirGen.beforeRegisterAllocation(); } - private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap> blockMap) { + private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap> blockMap) { if (lirGenRes.getLIR().getLIRforBlock(b) == null) { for (Block pred : b.getPredecessors()) { if (!b.isLoopHeader() || !pred.isLoopEnd()) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Tue Mar 17 12:05:51 2015 +0100 @@ -92,7 +92,7 @@ private ValueNode currentInstruction; private ValueNode lastInstructionPrinted; // Debugging only - private Map, List> matchRules; + private Map, List> matchRules; public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) { this.gen = gen; @@ -116,18 +116,18 @@ * @param node A node that produces a result value. */ @Override - public Value operand(ValueNode node) { + public Value operand(Node node) { Value operand = getOperand(node); assert operand != null : String.format("missing operand for %1s", node); return operand; } @Override - public boolean hasOperand(ValueNode node) { + public boolean hasOperand(Node node) { return getOperand(node) != null; } - private Value getOperand(ValueNode node) { + private Value getOperand(Node node) { if (nodeOperands == null) { return null; } @@ -162,7 +162,7 @@ * Used by the {@link MatchStatement} machinery to override the generation LIR for some * ValueNodes. */ - public void setMatchResult(ValueNode x, Value operand) { + public void setMatchResult(Node x, Value operand) { assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; assert operand instanceof ComplexMatchValue || x.getUsageCount() == 1 : "interior matches must be single user"; assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice"; @@ -191,7 +191,7 @@ gen.append(op); } - public void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap) { + public void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap) { gen.doBlockStart(block); if (block == gen.getResult().getLIR().getControlFlowGraph().getStartBlock()) { @@ -201,41 +201,44 @@ assert block.getPredecessorCount() > 0; } - List nodes = blockMap.get(block); + List nodes = blockMap.get(block); // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups // of instructions matchComplexExpressions(nodes); for (int i = 0; i < nodes.size(); i++) { - ValueNode valueNode = nodes.get(i); - if (Options.TraceLIRGeneratorLevel.getValue() >= 3) { - TTY.println("LIRGen for " + valueNode); - } - Value operand = getOperand(valueNode); - if (operand == null) { - if (!peephole(valueNode)) { - try { - doRoot(valueNode); - } catch (GraalInternalError e) { - throw GraalGraphInternalError.transformAndAddContext(e, valueNode); - } catch (Throwable e) { - throw new GraalGraphInternalError(e).addContext(valueNode); + Node node = nodes.get(i); + if (node instanceof ValueNode) { + ValueNode valueNode = (ValueNode) node; + if (Options.TraceLIRGeneratorLevel.getValue() >= 3) { + TTY.println("LIRGen for " + valueNode); + } + Value operand = getOperand(valueNode); + if (operand == null) { + if (!peephole(valueNode)) { + try { + doRoot(valueNode); + } catch (GraalInternalError e) { + throw GraalGraphInternalError.transformAndAddContext(e, valueNode); + } catch (Throwable e) { + throw new GraalGraphInternalError(e).addContext(valueNode); + } } + } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) { + // Doesn't need to be evaluated + Debug.log("interior match for %s", valueNode); + } else if (operand instanceof ComplexMatchValue) { + Debug.log("complex match for %s", valueNode); + ComplexMatchValue match = (ComplexMatchValue) operand; + operand = match.evaluate(this); + if (operand != null) { + setResult(valueNode, operand); + } + } else { + // There can be cases in which the result of an instruction is already set + // before by other instructions. } - } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) { - // Doesn't need to be evaluated - Debug.log("interior match for %s", valueNode); - } else if (operand instanceof ComplexMatchValue) { - Debug.log("complex match for %s", valueNode); - ComplexMatchValue match = (ComplexMatchValue) operand; - operand = match.evaluate(this); - if (operand != null) { - setResult(valueNode, operand); - } - } else { - // There can be cases in which the result of an instruction is already set - // before by other instructions. } } @@ -256,19 +259,19 @@ gen.doBlockEnd(block); } - protected void matchComplexExpressions(List nodes) { + protected void matchComplexExpressions(List nodes) { if (matchRules != null) { try (Scope s = Debug.scope("MatchComplexExpressions")) { if (LogVerbose.getValue()) { int i = 0; - for (ValueNode node : nodes) { + for (Node node : nodes) { Debug.log("%d: (%s) %1S", i++, node.getUsageCount(), node); } } // Match the nodes in backwards order to encourage longer matches. for (int index = nodes.size() - 1; index >= 0; index--) { - ValueNode node = nodes.get(index); + Node node = nodes.get(index); if (getOperand(node) != null) { continue; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Tue Mar 17 12:05:51 2015 +0100 @@ -30,7 +30,7 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.match.MatchPattern.Result; import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.virtual.*; @@ -39,15 +39,15 @@ */ public class MatchContext { - private final ValueNode root; + private final Node root; - private final List nodes; + private final List nodes; private final MatchStatement rule; private Map namedNodes; - private ArrayList consumed; + private ArrayList consumed; private int startIndex; @@ -56,16 +56,16 @@ private final NodeLIRBuilder builder; private static class NamedNode { - final Class type; - final ValueNode value; + final Class type; + final Node value; - NamedNode(Class type, ValueNode value) { + NamedNode(Class type, Node value) { this.type = type; this.value = value; } } - public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List nodes) { + public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, Node node, List nodes) { this.builder = builder; this.rule = rule; this.root = node; @@ -75,11 +75,11 @@ startIndex = endIndex = index; } - public ValueNode getRoot() { + public Node getRoot() { return root; } - public Result captureNamedValue(String name, Class type, ValueNode value) { + public Result captureNamedValue(String name, Class type, Node value) { if (namedNodes == null) { namedNodes = new HashMap<>(2); } @@ -99,7 +99,7 @@ public Result validate() { // Ensure that there's no unsafe work in between these operations. for (int i = startIndex; i <= endIndex; i++) { - ValueNode node = nodes.get(i); + Node node = nodes.get(i); if (node instanceof VirtualObjectNode || node instanceof FloatingNode) { // The order of evaluation of these nodes controlled by data dependence so they // don't interfere with this match. @@ -108,7 +108,7 @@ if (LogVerbose.getValue()) { Debug.log("unexpected node %s", node); for (int j = startIndex; j <= endIndex; j++) { - ValueNode theNode = nodes.get(j); + Node theNode = nodes.get(j); Debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.getUsageCount(), theNode); } } @@ -131,7 +131,7 @@ Debug.log("with nodes %s", rule.formatMatch(root)); } if (consumed != null) { - for (ValueNode node : consumed) { + for (Node node : consumed) { // All the interior nodes should be skipped during the normal doRoot calls in // NodeLIRBuilder so mark them as interior matches. The root of the match will get a // closure which will be evaluated to produce the final LIR. @@ -146,7 +146,7 @@ * * @return Result.OK if the node can be safely consumed. */ - public Result consume(ValueNode node) { + public Result consume(Node node) { assert node.getUsageCount() <= 1 : "should have already been checked"; // Check NOT_IN_BLOCK first since that usually implies ALREADY_USED @@ -174,7 +174,7 @@ * @return the matched node * @throws GraalInternalError is the named node doesn't exist. */ - public ValueNode namedNode(String name) { + public Node namedNode(String name) { if (namedNodes != null) { NamedNode value = namedNodes.get(name); if (value != null) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Tue Mar 17 12:05:51 2015 +0100 @@ -25,7 +25,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; /** * A simple recursive pattern matcher for a DAG of nodes. @@ -50,11 +49,11 @@ static class Result { final MatchResultCode code; - final ValueNode node; + final Node node; final MatchPattern matcher; - Result(MatchResultCode result, ValueNode node, MatchPattern matcher) { + Result(MatchResultCode result, Node node, MatchPattern matcher) { this.code = result; this.node = node; this.matcher = matcher; @@ -75,32 +74,32 @@ private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null); private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null); - static Result wrongClass(ValueNode node, MatchPattern matcher) { + static Result wrongClass(Node node, MatchPattern matcher) { MatchResult_WRONG_CLASS.increment(); return Debug.isEnabled() ? new Result(MatchResultCode.WRONG_CLASS, node, matcher) : CACHED_WRONG_CLASS; } - static Result namedValueMismatch(ValueNode node, MatchPattern matcher) { + static Result namedValueMismatch(Node node, MatchPattern matcher) { MatchResult_NAMED_VALUE_MISMATCH.increment(); return Debug.isEnabled() ? new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher) : CACHED_NAMED_VALUE_MISMATCH; } - static Result tooManyUsers(ValueNode node, MatchPattern matcher) { + static Result tooManyUsers(Node node, MatchPattern matcher) { MatchResult_TOO_MANY_USERS.increment(); return Debug.isEnabled() ? new Result(MatchResultCode.TOO_MANY_USERS, node, matcher) : CACHED_TOO_MANY_USERS; } - static Result notInBlock(ValueNode node, MatchPattern matcher) { + static Result notInBlock(Node node, MatchPattern matcher) { MatchResult_NOT_IN_BLOCK.increment(); return Debug.isEnabled() ? new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher) : CACHED_NOT_IN_BLOCK; } - static Result notSafe(ValueNode node, MatchPattern matcher) { + static Result notSafe(Node node, MatchPattern matcher) { MatchResult_NOT_SAFE.increment(); return Debug.isEnabled() ? new Result(MatchResultCode.NOT_SAFE, node, matcher) : CACHED_NOT_SAFE; } - static Result alreadyUsed(ValueNode node, MatchPattern matcher) { + static Result alreadyUsed(Node node, MatchPattern matcher) { MatchResult_ALREADY_USED.increment(); return Debug.isEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED; } @@ -121,7 +120,7 @@ /** * The expected type of the node. It must match exactly. */ - private final Class nodeClass; + private final Class nodeClass; /** * An optional name for this node. A name can occur multiple times in a match and that name must @@ -151,7 +150,7 @@ this(null, name, singleUser); } - public MatchPattern(Class nodeClass, String name, boolean singleUser) { + public MatchPattern(Class nodeClass, String name, boolean singleUser) { this.nodeClass = nodeClass; this.name = name; this.singleUser = singleUser; @@ -159,7 +158,7 @@ this.inputs = null; } - private MatchPattern(Class nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) { + private MatchPattern(Class nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) { assert inputs == null || inputs.length == patterns.length; this.nodeClass = nodeClass; this.name = name; @@ -168,23 +167,23 @@ this.inputs = inputs; } - public MatchPattern(Class nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) { + public MatchPattern(Class nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) { this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs); } - public MatchPattern(Class nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) { + public MatchPattern(Class nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) { this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs); } - public MatchPattern(Class nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) { + public MatchPattern(Class nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) { this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs); } - Class nodeClass() { + Class nodeClass() { return nodeClass; } - private Result matchType(ValueNode node) { + private Result matchType(Node node) { if (nodeClass != null && node.getClass() != nodeClass) { return Result.wrongClass(node, this); } @@ -198,7 +197,7 @@ * @param context * @return Result.OK is the pattern can be safely matched. */ - Result matchUsage(ValueNode node, MatchContext context) { + Result matchUsage(Node node, MatchContext context) { Result result = matchUsage(node, context, true); if (result == Result.OK) { result = context.validate(); @@ -206,7 +205,7 @@ return result; } - private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) { + private Result matchUsage(Node node, MatchContext context, boolean atRoot) { Result result = matchType(node); if (result != Result.OK) { return result; @@ -240,11 +239,11 @@ * @param statement * @return Result.OK if the shape of the pattern matches. */ - public Result matchShape(ValueNode node, MatchStatement statement) { + public Result matchShape(Node node, MatchStatement statement) { return matchShape(node, statement, true); } - private Result matchShape(ValueNode node, MatchStatement statement, boolean atRoot) { + private Result matchShape(Node node, MatchStatement statement, boolean atRoot) { Result result = matchType(node); if (result != Result.OK) { return result; @@ -271,7 +270,7 @@ * rule. It's assumed that a match has already succeeded against this rule, otherwise the * printing may produce exceptions. */ - public String formatMatch(ValueNode root) { + public String formatMatch(Node root) { String result = String.format("%s", root); if (patterns.length == 0) { return result; @@ -288,8 +287,8 @@ } } - private ValueNode getInput(int index, ValueNode node) { - return (ValueNode) inputs[index].get(node); + private Node getInput(int index, Node node) { + return inputs[index].get(node); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Tue Mar 17 12:05:51 2015 +0100 @@ -32,7 +32,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; public class MatchRuleRegistry { @@ -45,7 +44,7 @@ * @param names * @return an array of Position objects corresponding to the named fields. */ - public static Position[] findPositions(NodeClass nodeClass, String[] names) { + public static Position[] findPositions(NodeClass nodeClass, String[] names) { Position[] result = new Position[names.length]; for (int i = 0; i < names.length; i++) { Edges edges = nodeClass.getInputEdges(); @@ -61,7 +60,7 @@ return result; } - private static final HashMap, Map, List>> registry = new HashMap<>(); + private static final HashMap, Map, List>> registry = new HashMap<>(); /** * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass. @@ -69,11 +68,11 @@ * @param theClass * @return the set of {@link MatchStatement}s applicable to theClass. */ - public static synchronized Map, List> lookup(Class theClass) { - Map, List> result = registry.get(theClass); + public static synchronized Map, List> lookup(Class theClass) { + Map, List> result = registry.get(theClass); if (result == null) { - Map, List> rules = createRules(theClass); + Map, List> rules = createRules(theClass); registry.put(theClass, rules); assert registry.get(theClass) == rules; result = rules; @@ -81,7 +80,7 @@ if (LogVerbose.getValue()) { try (Scope s = Debug.scope("MatchComplexExpressions")) { Debug.log("Match rules for %s", theClass.getSimpleName()); - for (Entry, List> entry : result.entrySet()) { + for (Entry, List> entry : result.entrySet()) { Debug.log(" For node class: %s", entry.getKey()); for (MatchStatement statement : entry.getValue()) { Debug.log(" %s", statement.getPattern()); @@ -101,7 +100,7 @@ * This is a separate, public method so that external clients can create rules with a custom * lookup and without the default caching behavior. */ - public static Map, List> createRules(Class theClass) { + public static Map, List> createRules(Class theClass) { HashMap, MatchStatementSet> matchSets = new HashMap<>(); Iterable sl = Services.load(MatchStatementSet.class); for (MatchStatementSet rules : sl) { @@ -110,14 +109,14 @@ // Walk the class hierarchy collecting lists and merge them together. The subclass // rules are first which gives them preference over earlier rules. - Map, List> rules = new HashMap<>(); + Map, List> rules = new HashMap<>(); Class currentClass = theClass; do { MatchStatementSet matchSet = matchSets.get(currentClass); if (matchSet != null) { List statements = matchSet.statements(); for (MatchStatement statement : statements) { - Class nodeClass = statement.getPattern().nodeClass(); + Class nodeClass = statement.getPattern().nodeClass(); List current = rules.get(nodeClass); if (current == null) { current = new ArrayList<>(); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Tue Mar 17 12:05:51 2015 +0100 @@ -33,11 +33,10 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; /** * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace - * one or more {@link ValueNode}s with a single {@link Value}. + * one or more {@link Node}s with a single {@link Value}. */ public class MatchStatement { @@ -80,7 +79,7 @@ * @return true if the statement matched something and set a {@link ComplexMatchResult} to be * evaluated by the NodeLIRBuilder. */ - public boolean generate(NodeLIRBuilder builder, int index, ValueNode node, List nodes) { + public boolean generate(NodeLIRBuilder builder, int index, Node node, List nodes) { assert index == nodes.indexOf(node); // Check that the basic shape matches Result result = pattern.matchShape(node, this); @@ -115,8 +114,7 @@ /** * @param context - * @return the ValueNodes captured by the match rule in the order expected by the - * generatorMethod + * @return the Nodes captured by the match rule in the order expected by the generatorMethod */ private Object[] buildArgList(MatchContext context) { Object[] result = new Object[arguments.length]; @@ -133,7 +131,7 @@ return result; } - public String formatMatch(ValueNode root) { + public String formatMatch(Node root) { return pattern.formatMatch(root); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java Tue Mar 17 12:05:51 2015 +0100 @@ -528,22 +528,56 @@ } index++; } - int count = getCount(); + int count = curOffsets.length; while (index < count) { NodeList list = getNodeList(node, curOffsets, index); - if (list != null) { - for (int i = 0; i < list.size(); ++i) { - Node curNode = list.get(i); - if (curNode != null) { - consumer.accept(node, curNode); - } + acceptHelper(node, consumer, list); + index++; + } + } + + private static void acceptHelper(Node node, BiConsumer consumer, NodeList list) { + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + consumer.accept(node, curNode); } } - index++; } } public long[] getOffsets() { return this.offsets; } + + public void pushAll(Node node, NodeStack stack) { + int index = 0; + int curDirectCount = this.directCount; + final long[] curOffsets = this.offsets; + while (index < curDirectCount) { + Node curNode = getNode(node, curOffsets, index); + if (curNode != null) { + stack.push(curNode); + } + index++; + } + int count = curOffsets.length; + while (index < count) { + NodeList list = getNodeList(node, curOffsets, index); + pushAllHelper(stack, list); + index++; + } + } + + private static void pushAllHelper(NodeStack stack, NodeList list) { + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + Node curNode = list.get(i); + if (curNode != null) { + stack.push(curNode); + } + } + } + } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Mar 17 12:05:51 2015 +0100 @@ -884,18 +884,22 @@ if (condition) { return true; } else { - throw new VerificationError(message, args).addContext(this); + throw fail(message, args); } } public boolean assertFalse(boolean condition, String message, Object... args) { if (condition) { - throw new VerificationError(message, args).addContext(this); + throw fail(message, args); } else { return true; } } + protected VerificationError fail(String message, Object... args) throws GraalGraphInternalError { + throw new VerificationError(message, args).addContext(this); + } + public Iterable cfgPredecessors() { if (predecessor == null) { return Collections.emptySet(); @@ -1070,4 +1074,8 @@ public boolean valueEquals(Node other) { return getNodeClass().dataEquals(this, other); } + + public final void pushInputs(NodeStack stack) { + getNodeClass().getInputEdges().pushAll(this, stack); + } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeStack.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeStack.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.graph; + +public class NodeStack { + + private static final int INITIAL_SIZE = 8; + + protected Node[] values; + protected int tos; + + public NodeStack() { + values = new Node[INITIAL_SIZE]; + } + + public void push(Node n) { + int newIndex = tos++; + int valuesLength = values.length; + if (newIndex >= valuesLength) { + Node[] newValues = new Node[valuesLength << 1]; + System.arraycopy(values, 0, newValues, 0, valuesLength); + values = newValues; + } + values[newIndex] = n; + } + + public Node pop() { + assert tos > 0 : "stack must be non-empty"; + return values[--tos]; + } + + public Node peek() { + assert tos > 0 : "stack must be non-empty"; + return values[tos - 1]; + } + + public boolean isEmpty() { + return tos == 0; + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Mar 17 12:05:51 2015 +0100 @@ -333,7 +333,7 @@ return new AMD64RawNativeCallNode(returnType, functionPointer, args); } }; - Backend backend = HotSpotGraalRuntime.runtime().getBackend(AMD64.class); + Backend backend = HotSpotGraalRuntime.runtime().getHostBackend(); return new HotSpotNativeFunctionInterface(HotSpotGraalRuntime.runtime().getHostProviders(), factory, backend, config.dllLoad, config.dllLookup, config.rtldDefault); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.hotspot.HotSpotGraalRuntime; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64Move.MemOp; -import com.oracle.graal.lir.asm.*; - -public class AMD64HotSpotCompare { - - @Opcode("CMP") - public static final class HotSpotCompareConstantOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotCompareConstantOp.class); - - @Use({REG}) protected AllocatableValue x; - protected JavaConstant y; - - public HotSpotCompareConstantOp(AllocatableValue x, JavaConstant y) { - super(TYPE); - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - assert isRegister(x); - if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) { - // compressed null - masm.testl(asRegister(x), asRegister(x)); - } else if (y instanceof HotSpotObjectConstant) { - HotSpotObjectConstant yConst = (HotSpotObjectConstant) y; - if (yConst.isCompressed()) { - // compressed oop - crb.recordInlineDataInCode(y); - masm.cmpl(asRegister(x), 0xDEADDEAD); - } else { - // uncompressed oop - AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(y, 8); - masm.cmpq(asRegister(x), patch); - } - } else if (y instanceof HotSpotMetaspaceConstant) { - boolean isImmutable = GraalOptions.ImmutableCode.getValue(); - boolean generatePIC = GraalOptions.GeneratePIC.getValue(); - if (y.getKind() == Kind.Int) { - // compressed metaspace pointer - crb.recordInlineDataInCode(y); - if (isImmutable && generatePIC) { - Kind hostWordKind = HotSpotGraalRuntime.getHostWordKind(); - int alignment = hostWordKind.getBitCount() / Byte.SIZE; - // recordDataReferenceInCode forces the mov to be rip-relative - masm.cmpl(asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(JavaConstant.INT_0, alignment)); - } else { - masm.cmpl(asRegister(x), y.asInt()); - } - } else { - // uncompressed metaspace pointer - if (isImmutable && generatePIC) { - crb.recordInlineDataInCode(y); - Kind hostWordKind = HotSpotGraalRuntime.getHostWordKind(); - int alignment = hostWordKind.getBitCount() / Byte.SIZE; - // recordDataReferenceInCode forces the mov to be rip-relative - masm.cmpq(asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(JavaConstant.INT_0, alignment)); - } else { - AMD64Address patch = (AMD64Address) crb.recordDataReferenceInCode(y, 8); - masm.cmpq(asRegister(x), patch); - } - } - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - } - - @Opcode("CMP") - public static final class HotSpotCompareMemoryConstantOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotCompareMemoryConstantOp.class); - - protected JavaConstant y; - - public HotSpotCompareMemoryConstantOp(Kind kind, AMD64AddressValue x, JavaConstant y, LIRFrameState state) { - super(TYPE, kind, x, state); - this.y = y; - } - - @Override - protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(y)) { - // compressed null - masm.cmpl(address.toAddress(), 0); - } else if (y instanceof HotSpotObjectConstant) { - HotSpotObjectConstant yConst = (HotSpotObjectConstant) y; - if (yConst.isCompressed() && crb.target.inlineObjects) { - // compressed oop - crb.recordInlineDataInCode(y); - masm.cmpl(address.toAddress(), 0xDEADDEAD); - } else { - // uncompressed oop - throw GraalInternalError.shouldNotReachHere(); - } - } else if (y instanceof HotSpotMetaspaceConstant) { - if (y.getKind() == Kind.Int) { - // compressed metaspace pointer - crb.recordInlineDataInCode(y); - masm.cmpl(address.toAddress(), y.asInt()); - } else if (y.getKind() == Kind.Long && NumUtil.is32bit(y.asLong())) { - // uncompressed metaspace pointer - crb.recordInlineDataInCode(y); - masm.cmpq(address.toAddress(), (int) y.asLong()); - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - } - -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareConstOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareConstOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64HotSpotCompareConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCompareConstOp.class); + + @Opcode private final AMD64MIOp opcode; + + @Use({REG, STACK}) protected AllocatableValue x; + protected HotSpotConstant y; + + public AMD64HotSpotCompareConstOp(AMD64MIOp opcode, AllocatableValue x, HotSpotConstant y) { + super(TYPE); + this.opcode = opcode; + this.x = x; + this.y = y; + + assert y.isCompressed(); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + int imm32; + if (y instanceof HotSpotMetaspaceConstant) { + imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue(); + } else { + assert y instanceof HotSpotObjectConstant; + imm32 = 0xDEADDEAD; + } + + crb.recordInlineDataInCode(y); + if (isRegister(x)) { + opcode.emit(masm, DWORD, asRegister(x), imm32); + } else { + assert isStackSlot(x); + opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareMemoryConstOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareMemoryConstOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64HotSpotCompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCompareMemoryConstOp.class); + + @Opcode private final AMD64MIOp opcode; + + @Use({COMPOSITE}) protected AMD64AddressValue x; + protected HotSpotConstant y; + + @State protected LIRFrameState state; + + public AMD64HotSpotCompareMemoryConstOp(AMD64MIOp opcode, AMD64AddressValue x, HotSpotConstant y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.x = x; + this.y = y; + this.state = state; + + assert y.isCompressed(); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + int imm32; + if (y instanceof HotSpotMetaspaceConstant) { + imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue(); + } else { + assert y instanceof HotSpotObjectConstant; + imm32 = 0xDEADDEAD; + } + + crb.recordInlineDataInCode(y); + if (isRegister(x)) { + opcode.emit(masm, DWORD, asRegister(x), imm32); + } else { + assert isStackSlot(x); + opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32); + } + } + + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotComparePatchOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotComparePatchOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64HotSpotComparePatchOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotComparePatchOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + protected HotSpotConstant y; + + public AMD64HotSpotComparePatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, HotSpotConstant y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Address addr = (AMD64Address) crb.recordDataReferenceInCode(y, size.getBytes()); + opcode.emit(masm, size, asRegister(x), addr); + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java Tue Mar 17 12:05:51 2015 +0100 @@ -59,8 +59,8 @@ RegisterValue exception = rax.asValue(LIRKind.reference(Kind.Object)); RegisterValue exceptionPc = rdx.asValue(LIRKind.value(word)); CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc); - register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION)); - register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION)); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, any())); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, any())); if (PreferGraalStubs.getValue()) { link(new AMD64DeoptimizationStub(providers, target, config, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); @@ -69,7 +69,7 @@ if (config.useCRC32Intrinsics) { // This stub does callee saving - registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION); + registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any()); } super.initialize(providers, config); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,9 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; import static com.oracle.graal.hotspot.HotSpotBackend.*; import java.util.*; @@ -31,6 +34,7 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; @@ -120,11 +124,12 @@ List epilogueOps = new ArrayList<>(2); @Override - public void append(LIRInstruction op) { - super.append(op); + public I append(I op) { + I ret = super.append(op); if (op instanceof AMD64HotSpotEpilogueOp) { epilogueOps.add((AMD64HotSpotEpilogueOp) op); } + return ret; } @Override @@ -579,19 +584,35 @@ @Override protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) { - if (right instanceof HotSpotConstant) { - append(new AMD64HotSpotCompare.HotSpotCompareConstantOp(left, (JavaConstant) right)); + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(right)) { + append(new AMD64CompareOp(TEST, DWORD, left, left)); + } else if (right instanceof HotSpotConstant) { + HotSpotConstant c = (HotSpotConstant) right; + + boolean isImmutable = GraalOptions.ImmutableCode.getValue(); + boolean generatePIC = GraalOptions.GeneratePIC.getValue(); + if (c.isCompressed() && !(isImmutable && generatePIC)) { + append(new AMD64HotSpotCompareConstOp(CMP.getMIOpcode(DWORD, false), left, c)); + } else { + OperandSize size = c.isCompressed() ? DWORD : QWORD; + append(new AMD64HotSpotComparePatchOp(CMP.getRMOpcode(size), size, left, c)); + } } else { super.emitCompareOp(cmpKind, left, right); } } @Override - protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { - if (value instanceof HotSpotConstant) { - append(new AMD64HotSpotCompare.HotSpotCompareMemoryConstantOp(kind, address, value, state)); + protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) { + if (a.isNull()) { + append(new AMD64CompareMemoryConstOp(CMP.getMIOpcode(size, true), size, b, PrimitiveConstant.INT_0, state)); + return true; + } else if (a instanceof HotSpotConstant && size == DWORD) { + assert ((HotSpotConstant) a).isCompressed(); + append(new AMD64HotSpotCompareMemoryConstOp(CMP.getMIOpcode(size, false), b, (HotSpotConstant) a, state)); + return true; } else { - super.emitCompareMemoryConOp(kind, address, value, state); + return super.emitCompareMemoryConOp(size, a, b, state); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,14 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; import static com.oracle.graal.hotspot.HotSpotBackend.*; import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.*; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; @@ -270,27 +272,78 @@ return null; } + private ComplexMatchResult binaryReadCompressed(AMD64RMOp op, OperandSize size, ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { + if (canFormCompressedMemory(compress, location)) { + return builder -> getLIRGeneratorTool().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), makeCompressedAddress(compress, location), getState(access)); + } else { + return null; + } + } + @MatchRule("(Add value (Read=access (Compression=compress object) ConstantLocation=location))") + @MatchRule("(Add value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") + public ComplexMatchResult addMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return binaryReadCompressed(SSEOp.ADD, size, value, access, compress, location); + } else { + return binaryReadCompressed(ADD.getRMOpcode(size), size, value, access, compress, location); + } + } + @MatchRule("(Sub value (Read=access (Compression=compress object) ConstantLocation=location))") + @MatchRule("(Sub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") + public ComplexMatchResult subMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return binaryReadCompressed(SSEOp.SUB, size, value, access, compress, location); + } else { + return binaryReadCompressed(SUB.getRMOpcode(size), size, value, access, compress, location); + } + } + @MatchRule("(Mul value (Read=access (Compression=compress object) ConstantLocation=location))") + @MatchRule("(Mul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") + public ComplexMatchResult mulMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return binaryReadCompressed(SSEOp.MUL, size, value, access, compress, location); + } else { + return binaryReadCompressed(AMD64RMOp.IMUL, size, value, access, compress, location); + } + } + + @MatchRule("(And value (Read=access (Compression=compress object) ConstantLocation=location))") + @MatchRule("(And value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") + public ComplexMatchResult andMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryReadCompressed(AND.getRMOpcode(size), size, value, access, compress, location); + } + } + @MatchRule("(Or value (Read=access (Compression=compress object) ConstantLocation=location))") + @MatchRule("(Or value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") + public ComplexMatchResult orMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryReadCompressed(OR.getRMOpcode(size), size, value, access, compress, location); + } + } + @MatchRule("(Xor value (Read=access (Compression=compress object) ConstantLocation=location))") - @MatchRule("(And value (Read=access (Compression=compress object) ConstantLocation=location))") - @MatchRule("(Add value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") - @MatchRule("(Sub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") - @MatchRule("(Mul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") - @MatchRule("(Or value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") @MatchRule("(Xor value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") - @MatchRule("(And value (FloatingRead=access (Compression=compress object) ConstantLocation=location))") - public ComplexMatchResult binaryReadCompressed(BinaryNode root, ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { - if (canFormCompressedMemory(compress, location)) { - AMD64Arithmetic op = getOp(root, access); - if (op != null) { - return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeCompressedAddress(compress, location), - getState(access)); - } + public ComplexMatchResult xorMemoryCompressed(ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) { + OperandSize size = getMemorySize(access); + if (size.isXmmType()) { + return null; + } else { + return binaryReadCompressed(XOR.getRMOpcode(size), size, value, access, compress, location); } - return null; } @MatchRule("(Read (Compression=compress object) ConstantLocation=location)") diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java Tue Mar 17 12:05:51 2015 +0100 @@ -60,8 +60,8 @@ RegisterValue incomingExceptionPc = i1.asValue(LIRKind.value(word)); CallingConvention outgoingExceptionCc = new CallingConvention(0, ILLEGAL, outgoingException, outgoingExceptionPc); CallingConvention incomingExceptionCc = new CallingConvention(0, ILLEGAL, incomingException, incomingExceptionPc); - register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION)); - register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION)); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any())); + register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, any())); if (PreferGraalStubs.getValue()) { link(new SPARCDeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.test; +import static com.oracle.graal.nodes.spi.Replacements.*; + import java.io.*; import java.lang.reflect.*; import java.security.*; @@ -58,6 +60,8 @@ @Test public void testEncryptSubstitution() throws Exception { + Assume.assumeTrue(SELF_RECURSIVE_INTRINSICS_ENABLED); + byte[] seed = {0x4, 0x7, 0x1, 0x1}; SecureRandom random = new SecureRandom(seed); KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES"); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -657,15 +657,13 @@ if (node instanceof WriteNode) { WriteNode write = (WriteNode) node; LocationIdentity obj = write.getLocationIdentity(); - if (obj instanceof ResolvedJavaField) { - if (((ResolvedJavaField) obj).getName().equals("barrierIndex")) { - /* - * A "barrierIndex" variable was found and is checked against the - * input barrier array. - */ - if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) { - return true; - } + if (obj.toString().equals("barrierIndex")) { + /* + * A "barrierIndex" variable was found and is checked against the input + * barrier array. + */ + if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) { + return true; } } } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Tue Mar 17 12:05:51 2015 +0100 @@ -119,17 +119,17 @@ public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); /** - * @see NewMultiArrayStubCall + * New multi array stub call. */ public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class); /** - * @see NewArrayStubCall + * New array stub. */ public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class); /** - * @see NewInstanceStubCall + * New insstance stub. */ public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Mar 17 12:05:51 2015 +0100 @@ -248,7 +248,7 @@ // compiled code entry as HotSpot does not guarantee they are final // values. int methodCompiledEntryOffset = runtime.getConfig().methodCompiledEntryOffset; - ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, graph.unique(new ConstantLocationNode(ANY_LOCATION, methodCompiledEntryOffset)), StampFactory.forKind(wordKind), + ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, graph.unique(new ConstantLocationNode(any(), methodCompiledEntryOffset)), StampFactory.forKind(wordKind), BarrierType.NONE)); loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), @@ -359,7 +359,7 @@ for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.TYPE)) { int size = osrLocal.getKind().getSlotCount(); int offset = localsOffset - (osrLocal.index() + size - 1) * 8; - IndexedLocationNode location = graph.unique(new IndexedLocationNode(ANY_LOCATION, offset, ConstantNode.forLong(0, graph), 1)); + IndexedLocationNode location = graph.unique(new IndexedLocationNode(any(), offset, ConstantNode.forLong(0, graph), 1)); ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE)); osrLocal.replaceAndDelete(load); graph.addBeforeFixed(migrationEnd, load); @@ -444,7 +444,7 @@ // We use LocationNode.ANY_LOCATION for the reads that access the vtable // entry as HotSpot does not guarantee that this is a final value. Stamp methodStamp = MethodPointerStamp.method(); - ReadNode metaspaceMethod = graph.add(new ReadNode(hub, graph.unique(new ConstantLocationNode(ANY_LOCATION, vtableEntryOffset)), methodStamp, BarrierType.NONE)); + ReadNode metaspaceMethod = graph.add(new ReadNode(hub, graph.unique(new ConstantLocationNode(any(), vtableEntryOffset)), methodStamp, BarrierType.NONE)); return metaspaceMethod; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,11 @@ } @Override + public boolean isCompressed() { + return true; + } + + @Override public boolean isDefaultForKind() { return true; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,4 +28,6 @@ * Marker interface for hotspot specific constants. */ public interface HotSpotConstant extends Constant { + + boolean isCompressed(); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Tue Mar 17 12:05:51 2015 +0100 @@ -101,13 +101,17 @@ Registration r = new Registration(plugins, metaAccess, System.class); r.register0("currentTimeMillis", new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { - b.push(Kind.Long, b.append(new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long)))); + ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long)); + b.push(Kind.Long, b.append(foreignCall)); + foreignCall.setStateAfter(b.createStateAfter()); return true; } }); r.register0("nanoTime", new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { - b.push(Kind.Long, b.append(new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long)))); + ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long)); + b.push(Kind.Long, b.append(foreignCall)); + foreignCall.setStateAfter(b.createStateAfter()); return true; } }); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Mar 17 12:05:51 2015 +0100 @@ -151,21 +151,21 @@ registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(ARITHMETIC_POW, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); - registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION); + registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any()); - registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); - registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); - registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); - registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); - registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); - registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); + registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any()); + registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any()); + registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any()); + registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any()); + registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any()); + registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, any()); /* * We cannot use LEAF_SP here because on some architectures we have to align the stack * manually before calling into the VM. See {@link * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}. */ - registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION); + registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, any()); /* * This message call is registered twice, where the second one must only be used for calls @@ -174,32 +174,32 @@ registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS); - link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION))); - link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION))); + link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION))); + link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION))); link(new ExceptionHandlerStub(providers, foreignCalls.get(EXCEPTION_HANDLER))); - link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, ANY_LOCATION))); + link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, any()))); link(new VerifyOopStub(providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS))); linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, MARK_WORD_LOCATION); - linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); - linkForeignCall(providers, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); - linkForeignCall(providers, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); - linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); - linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, LEAF_SP, NOT_REEXECUTABLE, ANY_LOCATION); - linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); + linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any()); + linkForeignCall(providers, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any()); + linkForeignCall(providers, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any()); + linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any()); + linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, LEAF_SP, NOT_REEXECUTABLE, any()); + linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION); linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); - linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); + linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any()); linkForeignCall(providers, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, LEAF_NOFP, NOT_REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); - linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); + linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any()); // sometimes the same function is used for different kinds of arraycopy so check for // duplicates using a map. diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Tue Mar 17 12:05:51 2015 +0100 @@ -48,20 +48,22 @@ public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method); if (subst != null) { - // Forced inlining of intrinsics - return new InlineInfo(subst, true); + if (b.parsingReplacement() || InlineDuringParsing.getValue()) { + // Forced inlining of intrinsics + return new InlineInfo(subst, true, true); + } } if (b.parsingReplacement()) { assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null && !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); // Force inlining when parsing replacements - return new InlineInfo(method, true); + return new InlineInfo(method, true, true); } else { assert nodeIntrinsification.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(), method.format("%h.%n"), b); if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { - return new InlineInfo(method, false); + return new InlineInfo(method, false, false); } } return null; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,6 @@ public interface HotSpotMetaspaceConstant extends HotSpotConstant, VMConstant { - boolean isCompressed(); - Constant compress(CompressEncoding encoding); Constant uncompress(CompressEncoding encoding); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,6 @@ JavaConstant uncompress(); - boolean isCompressed(); - /** * Gets the resolved Java type of the object represented by this constant. */ diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Tue Mar 17 12:05:51 2015 +0100 @@ -48,6 +48,39 @@ * This value contains all flags as stored in the VM including internal ones. */ private final int modifiers; + private final LocationIdentity locationIdentity = new FieldLocationIdentity(this); + + public static class FieldLocationIdentity extends LocationIdentity { + HotSpotResolvedJavaFieldImpl inner; + + public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { + super(false); + this.inner = inner; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof FieldLocationIdentity) { + FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; + return inner.equals(fieldLocationIdentity.inner); + + } + return false; + } + + @Override + public int hashCode() { + return inner.hashCode(); + } + + @Override + public String toString() { + return inner.name; + } + } public HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) { this.holder = holder; @@ -229,4 +262,8 @@ } } } + + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java Tue Mar 17 12:05:51 2015 +0100 @@ -114,7 +114,7 @@ Stamp readStamp = KlassPointerStamp.klass(); LocationNode location; if (args.length == 2) { - location = makeLocation(b, args[1], ANY_LOCATION); + location = makeLocation(b, args[1], any()); } else { location = makeLocation(b, args[1], args[2]); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Tue Mar 17 12:05:51 2015 +0100 @@ -57,6 +57,7 @@ public HotSpotNativeFunctionInterface(HotSpotProviders providers, RawNativeCallNodeFactory factory, Backend backend, long dlopen, long dlsym, long rtldDefault) { this.rtldDefault = rtldDefault == HotSpotVMConfig.INVALID_RTLD_DEFAULT_HANDLE ? null : new HotSpotNativeLibraryHandle("RTLD_DEFAULT", rtldDefault); this.providers = providers; + assert backend != null; this.backend = backend; this.factory = factory; this.libraryLoadFunctionPointer = new HotSpotNativeFunctionPointer(dlopen, "os::dll_load"); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -57,7 +57,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -40,7 +40,7 @@ * A call to the runtime code {@code Deoptimization::fetch_unroll_info}. */ @NodeInfo(allowedUsageTypes = {InputType.Memory}) -public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi { +public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { public static final NodeClass TYPE = NodeClass.create(DeoptimizationFetchUnrollInfoCallNode.class); @Input SaveAllRegistersNode registerSaver; @@ -53,8 +53,8 @@ } @Override - public LocationIdentity[] getLocationIdentities() { - return foreignCalls.getKilledLocations(FETCH_UNROLL_INFO); + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); } public SaveRegistersOp getSaveRegistersOp() { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -49,7 +49,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import static com.oracle.graal.hotspot.HotSpotBackend.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.stubs.*; -import com.oracle.graal.hotspot.word.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -/** - * A call to the {@link NewArrayStub}. - */ -@NodeInfo -public final class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(NewArrayStubCall.class); - private static final Stamp defaultStamp = StampFactory.objectNonNull(); - - @Input ValueNode hub; - @Input ValueNode length; - - public NewArrayStubCall(ValueNode hub, ValueNode length) { - super(TYPE, defaultStamp); - this.hub = hub; - this.length = length; - } - - @Override - public boolean inferStamp() { - if (stamp() == defaultStamp && hub.isConstant()) { - updateStamp(StampFactory.exactNonNull(((HotSpotMetaspaceConstant) hub.asJavaConstant()).asResolvedJavaType())); - return true; - } - return false; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY); - Variable result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native Object call(KlassPointer hub, int length); -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import static com.oracle.graal.hotspot.HotSpotBackend.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.stubs.*; -import com.oracle.graal.hotspot.word.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -/** - * A call to the {@link NewInstanceStub}. - */ -@NodeInfo -public final class NewInstanceStubCall extends DeoptimizingStubCall implements LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(NewInstanceStubCall.class); - private static final Stamp defaultStamp = StampFactory.objectNonNull(); - - @Input ValueNode hub; - - public NewInstanceStubCall(ValueNode hub) { - super(TYPE, defaultStamp); - this.hub = hub; - } - - @Override - public boolean inferStamp() { - if (stamp() == defaultStamp && hub.isConstant()) { - updateStamp(StampFactory.exactNonNull(((HotSpotMetaspaceConstant) hub.asJavaConstant()).asResolvedJavaType())); - return true; - } - return false; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_INSTANCE); - Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native Object call(KlassPointer hub); -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import static com.oracle.graal.hotspot.HotSpotBackend.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.word.*; - -/** - * Node implementing a call to {@code GraalRuntime::new_multi_array}. - */ -@NodeInfo -public final class NewMultiArrayStubCall extends ForeignCallNode { - - public static final NodeClass TYPE = NodeClass.create(NewMultiArrayStubCall.class); - private static final Stamp defaultStamp = StampFactory.objectNonNull(); - - @Input ValueNode hub; - @Input ValueNode dims; - protected final int rank; - - public NewMultiArrayStubCall(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode hub, int rank, ValueNode dims) { - super(TYPE, foreignCalls, NEW_MULTI_ARRAY, defaultStamp); - this.hub = hub; - this.rank = rank; - this.dims = dims; - } - - @Override - public boolean inferStamp() { - if (stamp() == defaultStamp && hub.isConstant()) { - updateStamp(StampFactory.exactNonNull(((HotSpotMetaspaceConstant) hub.asJavaConstant()).asResolvedJavaType())); - return true; - } - return false; - } - - @Override - protected Value[] operands(NodeLIRBuilderTool gen) { - return new Value[]{gen.operand(hub), JavaConstant.forInt(rank), gen.operand(dims)}; - } - - @NodeIntrinsic - public static native Object call(Word hub, @ConstantNodeParameter int rank, Word dims); -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -66,6 +66,6 @@ public static native long saveAllRegisters(); public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -40,7 +40,7 @@ * A call to the runtime code implementing the uncommon trap logic. */ @NodeInfo(allowedUsageTypes = {InputType.Memory}) -public final class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi { +public final class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { public static final NodeClass TYPE = NodeClass.create(UncommonTrapCallNode.class); @Input ValueNode trapRequest; @@ -55,8 +55,8 @@ } @Override - public LocationIdentity[] getLocationIdentities() { - return foreignCalls.getKilledLocations(UNCOMMON_TRAP); + public LocationIdentity getLocationIdentity() { + return LocationIdentity.any(); } public SaveRegistersOp getSaveRegistersOp() { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Tue Mar 17 12:05:51 2015 +0100 @@ -89,7 +89,7 @@ private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass); - Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, Kind.Object, LocationIdentity.any()); Word kAddr = fromWordBase(Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte))); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Tue Mar 17 12:05:51 2015 +0100 @@ -70,7 +70,7 @@ @MethodSubstitution(isStatic = false) static int encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); - Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.any()); if (getAESCryptClass().isInstance(embeddedCipher)) { Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true); @@ -83,7 +83,7 @@ @MethodSubstitution(isStatic = false) static int decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); - Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.any()); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false); @@ -95,8 +95,8 @@ private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); - Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.ANY_LOCATION); - Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.any()); + Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, Kind.Object, LocationIdentity.any()); Word kAddr = Word.fromWordBase(Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte))); Word rAddr = Word.fromWordBase(Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte))); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Tue Mar 17 12:05:51 2015 +0100 @@ -569,7 +569,7 @@ public static Word loadWordFromObject(Object object, int offset) { ReplacementsUtil.staticAssert(offset != hubOffset(), "Use loadHubIntrinsic instead of loadWordFromObject"); - return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION); + return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.any()); } public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue Mar 17 12:05:51 2015 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.replacements; +import static com.oracle.graal.nodes.spi.Replacements.*; + import java.lang.reflect.*; import java.util.zip.*; @@ -62,7 +64,9 @@ replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class); - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); + if (SELF_RECURSIVE_INTRINSICS_ENABLED) { + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); + } } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Tue Mar 17 12:05:51 2015 +0100 @@ -147,12 +147,15 @@ result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, true); } else { new_stub.inc(); - result = NewInstanceStubCall.call(hub); + result = newInstance(HotSpotBackend.NEW_INSTANCE, hub); } profileAllocation("instance", size, typeContext); return piCast(verifyOop(result), StampFactory.forNodeIntrinsic()); } + @NodeIntrinsic(ForeignCallNode.class) + public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub); + @Snippet public static Object allocateInstanceDynamic(Class type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) { KlassPointer hub = ClassGetHubNode.readClass(type); @@ -201,12 +204,15 @@ result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true); } else { newarray_stub.inc(); - result = NewArrayStubCall.call(hub, length); + result = newArray(HotSpotBackend.NEW_ARRAY, hub, length); } profileAllocation("array", allocationSize, typeContext); return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); } + @NodeIntrinsic(ForeignCallNode.class) + public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length); + public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class); public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class); @@ -275,9 +281,12 @@ for (int i = 0; i < rank; i++) { dims.writeInt(i * 4, dimensions[i], INIT_LOCATION); } - return NewMultiArrayStubCall.call(hub, rank, dims); + return newArrayCall(HotSpotBackend.NEW_MULTI_ARRAY, hub, rank, dims); } + @NodeIntrinsic(ForeignCallNode.class) + public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word hub, int rank, Word dims); + /** * Maximum number of long stores to emit when zeroing an object with a constant size. Larger * objects have their bodies initialized in a loop. diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Tue Mar 17 12:05:51 2015 +0100 @@ -45,7 +45,7 @@ Object thread = javaThread.readObject(threadObjectOffset(), JAVA_THREAD_THREAD_OBJECT_LOCATION); if (thisObject == thread) { Word osThread = javaThread.readWord(osThreadOffset(), JAVA_THREAD_OSTHREAD_LOCATION); - boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), ANY_LOCATION) != 0; + boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), any()) != 0; if (!interrupted || !clearInterrupted) { return interrupted; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Tue Mar 17 12:05:51 2015 +0100 @@ -483,7 +483,7 @@ public static void validateObject(Object parent, Object child) { if (verifyOops() && child != null && !validateOop(VALIDATE_OBJECT, parent, child)) { log(true, "Verification ERROR, Parent: %p Child: %p\n", Word.fromObject(parent).rawValue(), Word.fromObject(child).rawValue()); - DirectObjectStoreNode.storeObject(null, 0, 0, null, LocationIdentity.ANY_LOCATION, Kind.Object); + DirectObjectStoreNode.storeObject(null, 0, 0, null, LocationIdentity.any(), Kind.Object); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -141,7 +141,7 @@ if (elementKind != null) { return NamedLocationIdentity.getArrayLocation(elementKind); } - return ANY_LOCATION; + return any(); } @NodeIntrinsic diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -119,7 +119,7 @@ if (elementKind != null) { return NamedLocationIdentity.getArrayLocation(elementKind); } - return ANY_LOCATION; + return any(); } @NodeIntrinsic diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java Tue Mar 17 12:05:51 2015 +0100 @@ -243,19 +243,19 @@ Unsigned destNonVectorEnd = destStart.add(nonVectorBytes); while (destOffset.belowThan(destNonVectorEnd)) { - ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION); + ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any()); destOffset = destOffset.add(1); srcOffset = srcOffset.add(1); } // Unsigned destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(8)); while (destOffset.belowThan(destVectorEnd)) { - ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, ANY_LOCATION), ANY_LOCATION); + ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, any()), any()); destOffset = destOffset.add(wordSize()); srcOffset = srcOffset.add(wordSize()); } // Do the last bytes each when it is required to have absolute alignment. while (!supportsUnalignedMemoryAccess && destOffset.belowThan(destEnd)) { - ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, ANY_LOCATION), ANY_LOCATION); + ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any()); destOffset = destOffset.add(1); srcOffset = srcOffset.add(1); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue Mar 17 12:05:51 2015 +0100 @@ -45,9 +45,9 @@ /** * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is - * called via {@link NewArrayStubCall} from the {@linkplain NewObjectSnippets inline} allocation - * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it - * calls out to the HotSpot C++ runtime to complete the allocation. + * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails. + * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++ + * runtime to complete the allocation. */ public class NewArrayStub extends SnippetStub { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue Mar 17 12:05:51 2015 +0100 @@ -45,9 +45,9 @@ /** * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is - * called via {@link NewInstanceStubCall} from the {@linkplain NewObjectSnippets inline} allocation - * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it - * calls out to the HotSpot C++ runtime for to complete the allocation. + * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails. + * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++ + * runtime for to complete the allocation. */ public class NewInstanceStub extends SnippetStub { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Tue Mar 17 12:05:51 2015 +0100 @@ -358,7 +358,7 @@ } } - protected abstract ValueNode genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value); + protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value); private void genStoreIndexed(Kind kind) { emitExplicitExceptions(frameState.peek(2), frameState.peek(1)); @@ -366,7 +366,7 @@ ValueNode value = frameState.pop(kind.getStackKind()); ValueNode index = frameState.ipop(); ValueNode array = frameState.apop(); - append(genStoreIndexed(array, index, kind, value)); + genStoreIndexed(array, index, kind, value); } private void stackOp(int opcode) { @@ -698,7 +698,7 @@ } private void maybeEagerlyResolve(int cpi, int bytecode) { - if (graphBuilderConfig.eagerResolving() || parsingReplacement()) { + if (graphBuilderConfig.eagerResolving() || replacementContext instanceof IntrinsicContext) { constantPool.loadReferencedType(cpi, bytecode); } } @@ -870,7 +870,7 @@ EXPLICIT_EXCEPTIONS.increment(); } - protected abstract ValueNode genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value); + protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value); private void genPutField(JavaField field) { emitExplicitExceptions(frameState.peek(1), null); @@ -878,7 +878,7 @@ ValueNode value = frameState.pop(field.getKind().getStackKind()); ValueNode receiver = frameState.apop(); if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - appendOptimizedStoreField(genStoreField(receiver, (ResolvedJavaField) field, value)); + genStoreField(receiver, (ResolvedJavaField) field, value); } else { handleUnresolvedStoreField(field, value, receiver); } @@ -903,16 +903,12 @@ private void genPutStatic(JavaField field) { ValueNode value = frameState.pop(field.getKind().getStackKind()); if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - appendOptimizedStoreField(genStoreField(null, (ResolvedJavaField) field, value)); + genStoreField(null, (ResolvedJavaField) field, value); } else { handleUnresolvedStoreField(field, value, null); } } - protected void appendOptimizedStoreField(ValueNode store) { - append(store); - } - protected void appendOptimizedLoadField(Kind kind, ValueNode load) { // append the load to the instruction ValueNode optimized = append(load); @@ -931,9 +927,9 @@ protected abstract void genReturn(ValueNode x, Kind kind); - protected abstract ValueNode genMonitorEnter(ValueNode x); + protected abstract void genMonitorEnter(ValueNode x, int bci); - protected abstract ValueNode genMonitorExit(ValueNode x, ValueNode returnValue); + protected abstract void genMonitorExit(ValueNode x, ValueNode returnValue, int bci); protected abstract void genJsr(int dest); @@ -1293,8 +1289,8 @@ case ATHROW : genThrow(); break; case CHECKCAST : genCheckCast(); break; case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop()); break; - case MONITOREXIT : genMonitorExit(frameState.apop(), null); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; case IFNULL : genIfNull(Condition.EQ); break; case IFNONNULL : genIfNull(Condition.NE); break; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java Tue Mar 17 12:05:51 2015 +0100 @@ -36,7 +36,9 @@ /** * Information about a snippet or method substitution currently being processed by the graph - * builder. + * builder. When in the scope of a replacement, the graph builder does not check the value kinds + * flowing through the JVM state since replacements can employ non-Java kinds to represent + * values such as raw machine words and pointers. */ public interface Replacement { @@ -82,6 +84,8 @@ StructuredGraph getGraph(); + FrameState createStateAfter(); + /** * Gets the parsing context for the method that inlines the method being parsed by this context. */ diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -352,10 +352,9 @@ if (method.isSynchronized()) { // add a monitor enter to the start block methodSynchronizedObject = synchronizedObject(frameState, method); - MonitorEnterNode monitorEnter = genMonitorEnter(methodSynchronizedObject); frameState.clearNonLiveLocals(startBlock, liveness, true); assert bci() == 0; - monitorEnter.setStateAfter(createFrameState(bci())); + genMonitorEnter(methodSynchronizedObject, bci()); } if (graphBuilderConfig.insertNonSafepointDebugInfo()) { @@ -761,8 +760,10 @@ } @Override - protected ValueNode genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) { - return new StoreIndexedNode(array, index, kind, value); + protected void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) { + StoreIndexedNode storeIndexed = new StoreIndexedNode(array, index, kind, value); + append(storeIndexed); + storeIndexed.setStateAfter(this.createStateAfter()); } @Override @@ -978,8 +979,10 @@ } @Override - protected ValueNode genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) { - return new StoreFieldNode(receiver, field, value); + protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) { + StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value); + append(storeFieldNode); + storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI())); } /** @@ -1135,7 +1138,7 @@ invoke = createInvoke(callTarget, resultType); } else { invoke = createInvokeWithException(callTarget, resultType); - AbstractBeginNode beginNode = currentGraph.add(new KillingBeginNode(LocationIdentity.ANY_LOCATION)); + AbstractBeginNode beginNode = currentGraph.add(new KillingBeginNode(LocationIdentity.any())); invoke.setNext(beginNode); lastInstr = beginNode; } @@ -1219,8 +1222,9 @@ return false; } } else { - if (context == null && !inlinedMethod.equals(targetMethod)) { - if (inlineInfo.adoptBeforeCallFrameState) { + if (context == null && inlineInfo.isReplacement) { + assert !inlinedMethod.equals(targetMethod); + if (inlineInfo.isIntrinsic) { context = new IntrinsicContext(targetMethod, inlinedMethod, args, bci); } else { context = new ReplacementContext(targetMethod, inlinedMethod); @@ -1306,6 +1310,7 @@ protected InvokeNode createInvoke(CallTargetNode callTarget, Kind resultType) { InvokeNode invoke = append(new InvokeNode(callTarget, bci())); frameState.pushReturn(resultType, invoke); + invoke.setStateAfter(createFrameState(stream.nextBCI())); return invoke; } @@ -1356,22 +1361,22 @@ } @Override - protected MonitorEnterNode genMonitorEnter(ValueNode x) { + protected void genMonitorEnter(ValueNode x, int bci) { MonitorIdNode monitorId = currentGraph.add(new MonitorIdNode(frameState.lockDepth())); MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId)); frameState.pushLock(x, monitorId); - return monitorEnter; + monitorEnter.setStateAfter(createFrameState(bci)); } @Override - protected MonitorExitNode genMonitorExit(ValueNode x, ValueNode escapedReturnValue) { + protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) { MonitorIdNode monitorId = frameState.peekMonitorId(); ValueNode lockedObject = frameState.popLock(); if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) { throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject))); } MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue)); - return monitorExit; + monitorExit.setStateAfter(createFrameState(bci)); } @Override @@ -1926,11 +1931,10 @@ private void synchronizedEpilogue(int bci, ValueNode currentReturnValue, Kind currentReturnValueKind) { if (method.isSynchronized()) { - MonitorExitNode monitorExit = genMonitorExit(methodSynchronizedObject, currentReturnValue); if (currentReturnValue != null) { frameState.push(currentReturnValueKind, currentReturnValue); } - monitorExit.setStateAfter(createFrameState(bci)); + genMonitorExit(methodSynchronizedObject, currentReturnValue, bci); assert !frameState.rethrowException(); } } @@ -1986,10 +1990,6 @@ } } - private boolean isBlockEnd(Node n) { - return n instanceof ControlSplitNode || n instanceof ControlSinkNode; - } - @Override protected void iterateBytecodesForBlock(BciBlock block) { if (block.isLoopHeader && !explodeLoops) { @@ -2058,26 +2058,15 @@ throw asParserError(e); } - if (lastInstr == null || isBlockEnd(lastInstr) || lastInstr.next() != null) { + if (lastInstr == null || lastInstr.next() != null) { break; } stream.next(); bci = stream.currentBCI(); - if (bci > block.endBci) { - frameState.clearNonLiveLocals(currentBlock, liveness, false); - } - if (lastInstr instanceof StateSplit) { - if (lastInstr instanceof BeginNode) { - // BeginNodes do not need a frame state - } else { - StateSplit stateSplit = (StateSplit) lastInstr; - if (stateSplit.stateAfter() == null) { - stateSplit.setStateAfter(createFrameState(bci)); - } - } - } + assert block == currentBlock; + assert !(lastInstr instanceof StateSplit) || lastInstr instanceof BeginNode || ((StateSplit) lastInstr).stateAfter() != null : lastInstr; lastInstr = finishInstruction(lastInstr, frameState); if (bci < endBCI) { if (bci > block.endBci) { @@ -2391,8 +2380,15 @@ } private FrameState createFrameState(int bci) { + if (currentBlock != null && bci > currentBlock.endBci) { + frameState.clearNonLiveLocals(currentBlock, liveness, false); + } return frameState.create(bci); } + + public FrameState createStateAfter() { + return createFrameState(stream.nextBCI()); + } } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Tue Mar 17 12:05:51 2015 +0100 @@ -75,22 +75,29 @@ public static class InlineInfo { /** - * The method to be inlined. If this is not equal to the {@code method} argument passed - * to {@link InlineInvokePlugin#getClass()}, the graph builder context interprets it as - * a {@linkplain GraphBuilderContext.Replacement replacement}. + * The method to be inlined. */ public final ResolvedJavaMethod methodToInline; /** + * Specifies if {@link #methodToInline} is to be considered a + * {@linkplain GraphBuilderContext.Replacement replacement} for the {@code method} + * passed to {@link InlineInvokePlugin#getInlineInfo}. + */ + public final boolean isReplacement; + + /** * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so, * any {@link StateSplit} node created in the (recursive) inlining scope will be given a * frame state that restarts the interpreter just before the intrinsified invocation. */ - public final boolean adoptBeforeCallFrameState; + public final boolean isIntrinsic; - public InlineInfo(ResolvedJavaMethod methodToInline, boolean adoptBeforeCallFrameState) { + public InlineInfo(ResolvedJavaMethod methodToInline, boolean isReplacement, boolean isIntrinsic) { this.methodToInline = methodToInline; - this.adoptBeforeCallFrameState = adoptBeforeCallFrameState; + this.isIntrinsic = isIntrinsic; + this.isReplacement = isReplacement; + assert !isIntrinsic || isReplacement : "cannot be an intrinsic without also being a replacement"; } } @@ -211,7 +218,7 @@ if (ALLOW_INVOCATION_PLUGIN_TO_DO_INLINING) { ResolvedJavaMethod subst = plugin.getSubstitute(); if (subst != null) { - return ((BytecodeParser) b).inline(null, targetMethod, new InlineInfo(subst, false), args); + return ((BytecodeParser) b).inline(null, targetMethod, new InlineInfo(subst, true, false), args); } } if (args.length == 0) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.java/src/com/oracle/graal/java/LocalLiveness.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/LocalLiveness.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/LocalLiveness.java Tue Mar 17 12:05:51 2015 +0100 @@ -53,24 +53,18 @@ boolean changed; int iteration = 0; do { - Debug.log("Iteration %d", iteration); + assert traceIteration(iteration); changed = false; for (int i = blocks.length - 1; i >= 0; i--) { BciBlock block = blocks[i]; int blockID = block.getId(); - // log statements in IFs because debugLiveX creates a new String - if (Debug.isLogEnabled()) { - Debug.logv(" start B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), - debugLiveGen(blockID), debugLiveKill(blockID)); - } + assert traceStart(block, blockID); boolean blockChanged = (iteration == 0); if (block.getSuccessorCount() > 0) { int oldCardinality = liveOutCardinality(blockID); for (BciBlock sux : block.getSuccessors()) { - if (Debug.isLogEnabled()) { - Debug.log(" Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId())); - } + assert traceSuccessor(sux); propagateLiveness(blockID, sux.getId()); } blockChanged |= (oldCardinality != liveOutCardinality(blockID)); @@ -78,10 +72,7 @@ if (blockChanged) { updateLiveness(blockID); - if (Debug.isLogEnabled()) { - Debug.logv(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), - debugLiveGen(blockID), debugLiveKill(blockID)); - } + assert traceEnd(block, blockID); } changed |= blockChanged; } @@ -89,6 +80,34 @@ } while (changed); } + private static boolean traceIteration(int iteration) { + Debug.log("Iteration %d", iteration); + return true; + } + + private boolean traceEnd(BciBlock block, int blockID) { + if (Debug.isLogEnabled()) { + Debug.logv(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), + debugLiveKill(blockID)); + } + return true; + } + + private boolean traceSuccessor(BciBlock sux) { + if (Debug.isLogEnabled()) { + Debug.log(" Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId())); + } + return true; + } + + private boolean traceStart(BciBlock block, int blockID) { + if (Debug.isLogEnabled()) { + Debug.logv(" start B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), + debugLiveKill(blockID)); + } + return true; + } + /** * Returns whether the local is live at the beginning of the given block. */ diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,10 @@ return s.toString(); } + public boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit) { + return value.equals(base) && index.equals(Value.ILLEGAL) && displacement >= 0 && displacement < implicitNullCheckLimit; + } + @Override public boolean equals(Object obj) { if (obj instanceof AMD64AddressValue) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Tue Mar 17 12:05:51 2015 +0100 @@ -23,460 +23,18 @@ package com.oracle.graal.lir.amd64; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.amd64.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; -import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.AMD64Move.MemOp; import com.oracle.graal.lir.asm.*; public enum AMD64Arithmetic { - - // @formatter:off - - IADD, ISUB, IMUL, IUMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR, - LADD, LSUB, LMUL, LUMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR, - FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR, - DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, - INEG, LNEG, INOT, LNOT, - SQRT, - L2I, B2I, S2I, B2L, S2L, I2L, - F2D, D2F, - I2F, I2D, - L2F, L2D, - MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L, - MOV_B2UI, MOV_B2UL, // Zero extending byte loads - - /* - * Converts a float/double to an int/long. The result of the conversion does not comply with Java semantics - * when the input is a NaN, infinity or the conversion result is greater than Integer.MAX_VALUE/Long.MAX_VALUE. - */ - F2I, D2I, F2L, D2L; - - // @formatter:on - - /** - * Unary operation with separate source and destination operand. - */ - public static final class Unary2Op extends AMD64LIRInstruction { - - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Unary2Op.class); - @Opcode private final AMD64Arithmetic opcode; - @Def({REG}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - - public Unary2Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - emit(crb, masm, opcode, result, x, null); - } - } - - /** - * Unary operation with separate source and destination operand but register only. - */ - public static final class Unary2RegOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Unary2RegOp.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG}) protected AllocatableValue result; - @Use({REG}) protected AllocatableValue x; - - public Unary2RegOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - emit(crb, masm, opcode, result, x, null); - } - } - - /** - * Unary operation with single operand for source and destination. - */ - public static class Unary1Op extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Unary1Op.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - - public Unary1Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - emit(crb, masm, opcode, result); - } - } - - /** - * Unary operation with separate memory source and destination operand. - */ - public static final class Unary2MemoryOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Unary2MemoryOp.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG}) protected AllocatableValue result; - - public Unary2MemoryOp(AMD64Arithmetic opcode, AllocatableValue result, Kind kind, AMD64AddressValue address, LIRFrameState state) { - super(TYPE, kind, address, state); - this.opcode = opcode; - this.result = result; - } - - @Override - public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - emit(crb, masm, opcode, result, address, null); - } - } - - /** - * Binary operation with two operands. The first source operand is combined with the - * destination. The second source operand may be a stack slot. - */ - public static class BinaryRegStack extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryRegStack.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - @Alive({REG, STACK}) protected AllocatableValue y; - - public BinaryRegStack(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - emit(crb, masm, opcode, result, y, null); - } - - @Override - public void verify() { - super.verify(); - assert differentRegisters(result, y) || sameRegister(x, y); - verifyKind(opcode, result, x, y); - } - } - - /** - * Binary operation with two operands. The first source operand is combined with the - * destination. The second source operand may be a stack slot. - */ - public static final class BinaryMemory extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryMemory.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG}) protected AllocatableValue x; - protected final Kind kind; - @Alive({COMPOSITE}) protected AMD64AddressValue location; - @State protected LIRFrameState state; - - public BinaryMemory(AMD64Arithmetic opcode, Kind kind, AllocatableValue result, AllocatableValue x, AMD64AddressValue location, LIRFrameState state) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - this.location = location; - this.kind = kind; - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - emit(crb, masm, opcode, result, location, null); - } - - @Override - public void verify() { - super.verify(); - assert differentRegisters(result, location) || sameRegister(x, location); - // verifyKind(opcode, result, x, location); - } - } - - /** - * Binary operation with two operands. The first source operand is combined with the - * destination. The second source operand must be a register. - */ - public static final class BinaryRegReg extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryRegReg.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - @Alive({REG}) protected AllocatableValue y; - - public BinaryRegReg(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - emit(crb, masm, opcode, result, y, null); - } - - @Override - public void verify() { - super.verify(); - assert differentRegisters(result, y) || sameRegister(x, y); - verifyKind(opcode, result, x, y); - } - } - - /** - * Binary operation with single source/destination operand and one constant. - */ - public static final class BinaryRegConst extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryRegConst.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - protected JavaConstant y; - - public BinaryRegConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, JavaConstant y) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - emit(crb, masm, opcode, result, y, null); - } - - @Override - public void verify() { - super.verify(); - verifyKind(opcode, result, x, y); - } - } - - /** - * Commutative binary operation with two operands. One of the operands is combined with the - * result. - */ - public static final class BinaryCommutative extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryCommutative.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - @Use({REG, STACK}) protected AllocatableValue y; - - public BinaryCommutative(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (sameRegister(result, y)) { - emit(crb, masm, opcode, result, x, null); - } else { - AMD64Move.move(crb, masm, result, x); - emit(crb, masm, opcode, result, y, null); - } - } - - @Override - public void verify() { - super.verify(); - verifyKind(opcode, result, x, y); - } - } - - /** - * Binary operation with separate source and destination and one constant operand. - */ - public static final class BinaryRegStackConst extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryRegStackConst.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - protected JavaConstant y; - - public BinaryRegStackConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, JavaConstant y) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (isRegister(x)) { - switch (opcode) { - case IMUL: - masm.imull(asIntReg(result), asIntReg(x), crb.asIntConst(y)); - break; - case LMUL: - masm.imulq(asLongReg(result), asLongReg(x), crb.asIntConst(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else { - assert isStackSlot(x); - switch (opcode) { - case IMUL: - masm.imull(asIntReg(result), (AMD64Address) crb.asIntAddr(x), crb.asIntConst(y)); - break; - case LMUL: - masm.imulq(asLongReg(result), (AMD64Address) crb.asLongAddr(x), crb.asIntConst(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - - @Override - public void verify() { - super.verify(); - verifyKind(opcode, result, x, y); - } - } - - public static final class MulHighOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MulHighOp.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def({REG}) public AllocatableValue lowResult; - @Def({REG}) public AllocatableValue highResult; - @Use({REG}) public AllocatableValue x; - @Use({REG, STACK}) public AllocatableValue y; - - public MulHighOp(AMD64Arithmetic opcode, LIRKind kind, AllocatableValue y) { - super(TYPE); - this.opcode = opcode; - this.x = AMD64.rax.asValue(kind); - this.y = y; - this.lowResult = AMD64.rax.asValue(kind); - this.highResult = AMD64.rdx.asValue(kind); - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (isRegister(y)) { - switch (opcode) { - case IMUL: - masm.imull(asRegister(y)); - break; - case IUMUL: - masm.mull(asRegister(y)); - break; - case LMUL: - masm.imulq(asRegister(y)); - break; - case LUMUL: - masm.mulq(asRegister(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else { - switch (opcode) { - case IMUL: - masm.imull((AMD64Address) crb.asAddress(y)); - break; - case IUMUL: - masm.mull((AMD64Address) crb.asAddress(y)); - break; - case LMUL: - masm.imulq((AMD64Address) crb.asAddress(y)); - break; - case LUMUL: - masm.mulq((AMD64Address) crb.asAddress(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - } - - public static final class DivRemOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DivRemOp.class); - - @Opcode private final AMD64Arithmetic opcode; - @Def public AllocatableValue divResult; - @Def public AllocatableValue remResult; - @Use protected AllocatableValue x; - @Alive protected AllocatableValue y; - @State protected LIRFrameState state; - - public DivRemOp(AMD64Arithmetic opcode, AllocatableValue x, AllocatableValue y, LIRFrameState state) { - super(TYPE); - this.opcode = opcode; - this.divResult = AMD64.rax.asValue(LIRKind.derive(x, y)); - this.remResult = AMD64.rdx.asValue(LIRKind.derive(x, y)); - this.x = x; - this.y = y; - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - emit(crb, masm, opcode, null, y, state); - } - - @Override - public void verify() { - super.verify(); - // left input in rax, right input in any register but rax and rdx, result quotient in - // rax, result remainder in rdx - assert asRegister(x).equals(AMD64.rax); - assert differentRegisters(y, AMD64.rax.asValue(), AMD64.rdx.asValue()); - verifyKind(opcode, divResult, x, y); - verifyKind(opcode, remResult, x, y); - } - } + FREM, + DREM; public static class FPDivRemOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FPDivRemOp.class); @@ -536,647 +94,8 @@ @Override public void verify() { super.verify(); - verifyKind(opcode, result, x, y); - } - } - - @SuppressWarnings("unused") - protected static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Arithmetic opcode, AllocatableValue result) { - switch (opcode) { - case INEG: - masm.negl(asIntReg(result)); - break; - case LNEG: - masm.negq(asLongReg(result)); - break; - case INOT: - masm.notl(asIntReg(result)); - break; - case LNOT: - masm.notq(asLongReg(result)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); + assert (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || + (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double); } } - - public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Arithmetic opcode, Value dst, Value src, LIRFrameState info) { - int exceptionOffset = -1; - if (isRegister(src)) { - switch (opcode) { - case IADD: - masm.addl(asIntReg(dst), asIntReg(src)); - break; - case ISUB: - masm.subl(asIntReg(dst), asIntReg(src)); - break; - case IAND: - masm.andl(asIntReg(dst), asIntReg(src)); - break; - case IMUL: - masm.imull(asIntReg(dst), asIntReg(src)); - break; - case IOR: - masm.orl(asIntReg(dst), asIntReg(src)); - break; - case IXOR: - masm.xorl(asIntReg(dst), asIntReg(src)); - break; - case ISHL: - assert asIntReg(src).equals(AMD64.rcx); - masm.shll(asIntReg(dst)); - break; - case ISHR: - assert asIntReg(src).equals(AMD64.rcx); - masm.sarl(asIntReg(dst)); - break; - case IUSHR: - assert asIntReg(src).equals(AMD64.rcx); - masm.shrl(asIntReg(dst)); - break; - case IROL: - assert asIntReg(src).equals(AMD64.rcx); - masm.roll(asIntReg(dst)); - break; - case IROR: - assert asIntReg(src).equals(AMD64.rcx); - masm.rorl(asIntReg(dst)); - break; - - case LADD: - masm.addq(asLongReg(dst), asLongReg(src)); - break; - case LSUB: - masm.subq(asLongReg(dst), asLongReg(src)); - break; - case LMUL: - masm.imulq(asLongReg(dst), asLongReg(src)); - break; - case LAND: - masm.andq(asLongReg(dst), asLongReg(src)); - break; - case LOR: - masm.orq(asLongReg(dst), asLongReg(src)); - break; - case LXOR: - masm.xorq(asLongReg(dst), asLongReg(src)); - break; - case LSHL: - assert asIntReg(src).equals(AMD64.rcx); - masm.shlq(asLongReg(dst)); - break; - case LSHR: - assert asIntReg(src).equals(AMD64.rcx); - masm.sarq(asLongReg(dst)); - break; - case LUSHR: - assert asIntReg(src).equals(AMD64.rcx); - masm.shrq(asLongReg(dst)); - break; - case LROL: - assert asIntReg(src).equals(AMD64.rcx); - masm.rolq(asLongReg(dst)); - break; - case LROR: - assert asIntReg(src).equals(AMD64.rcx); - masm.rorq(asLongReg(dst)); - break; - - case FADD: - masm.addss(asFloatReg(dst), asFloatReg(src)); - break; - case FSUB: - masm.subss(asFloatReg(dst), asFloatReg(src)); - break; - case FMUL: - masm.mulss(asFloatReg(dst), asFloatReg(src)); - break; - case FDIV: - masm.divss(asFloatReg(dst), asFloatReg(src)); - break; - case FAND: - masm.andps(asFloatReg(dst), asFloatReg(src)); - break; - case FOR: - masm.orps(asFloatReg(dst), asFloatReg(src)); - break; - case FXOR: - masm.xorps(asFloatReg(dst), asFloatReg(src)); - break; - - case DADD: - masm.addsd(asDoubleReg(dst), asDoubleReg(src)); - break; - case DSUB: - masm.subsd(asDoubleReg(dst), asDoubleReg(src)); - break; - case DMUL: - masm.mulsd(asDoubleReg(dst), asDoubleReg(src)); - break; - case DDIV: - masm.divsd(asDoubleReg(dst), asDoubleReg(src)); - break; - case DAND: - masm.andpd(asDoubleReg(dst), asDoubleReg(src)); - break; - case DOR: - masm.orpd(asDoubleReg(dst), asDoubleReg(src)); - break; - case DXOR: - masm.xorpd(asDoubleReg(dst), asDoubleReg(src)); - break; - - case SQRT: - masm.sqrtsd(asDoubleReg(dst), asDoubleReg(src)); - break; - - case B2I: - masm.movsbl(asIntReg(dst), asIntReg(src)); - break; - case S2I: - masm.movswl(asIntReg(dst), asIntReg(src)); - break; - case B2L: - masm.movsbq(asLongReg(dst), asIntReg(src)); - break; - case S2L: - masm.movswq(asLongReg(dst), asIntReg(src)); - break; - case I2L: - masm.movslq(asLongReg(dst), asIntReg(src)); - break; - case L2I: - masm.movl(asIntReg(dst), asLongReg(src)); - break; - case F2D: - masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src)); - break; - case D2F: - masm.cvtsd2ss(asFloatReg(dst), asDoubleReg(src)); - break; - case I2F: - masm.cvtsi2ssl(asFloatReg(dst), asIntReg(src)); - break; - case I2D: - masm.cvtsi2sdl(asDoubleReg(dst), asIntReg(src)); - break; - case L2F: - masm.cvtsi2ssq(asFloatReg(dst), asLongReg(src)); - break; - case L2D: - masm.cvtsi2sdq(asDoubleReg(dst), asLongReg(src)); - break; - case F2I: - masm.cvttss2sil(asIntReg(dst), asFloatReg(src)); - break; - case D2I: - masm.cvttsd2sil(asIntReg(dst), asDoubleReg(src)); - break; - case F2L: - masm.cvttss2siq(asLongReg(dst), asFloatReg(src)); - break; - case D2L: - masm.cvttsd2siq(asLongReg(dst), asDoubleReg(src)); - break; - case MOV_I2F: - masm.movdl(asFloatReg(dst), asIntReg(src)); - break; - case MOV_L2D: - masm.movdq(asDoubleReg(dst), asLongReg(src)); - break; - case MOV_F2I: - masm.movdl(asIntReg(dst), asFloatReg(src)); - break; - case MOV_D2L: - masm.movdq(asLongReg(dst), asDoubleReg(src)); - break; - - case IDIVREM: - case IDIV: - case IREM: - masm.cdql(); - exceptionOffset = masm.position(); - masm.idivl(asRegister(src)); - break; - - case LDIVREM: - case LDIV: - case LREM: - masm.cdqq(); - exceptionOffset = masm.position(); - masm.idivq(asRegister(src)); - break; - - case IUDIV: - case IUREM: - // Must zero the high 64-bit word (in RDX) of the dividend - masm.xorq(AMD64.rdx, AMD64.rdx); - exceptionOffset = masm.position(); - masm.divl(asRegister(src)); - break; - - case LUDIV: - case LUREM: - // Must zero the high 64-bit word (in RDX) of the dividend - masm.xorq(AMD64.rdx, AMD64.rdx); - exceptionOffset = masm.position(); - masm.divq(asRegister(src)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isConstant(src)) { - switch (opcode) { - case IADD: - masm.incrementl(asIntReg(dst), crb.asIntConst(src)); - break; - case ISUB: - masm.decrementl(asIntReg(dst), crb.asIntConst(src)); - break; - case IAND: - masm.andl(asIntReg(dst), crb.asIntConst(src)); - break; - case IOR: - masm.orl(asIntReg(dst), crb.asIntConst(src)); - break; - case IXOR: - masm.xorl(asIntReg(dst), crb.asIntConst(src)); - break; - case ISHL: - masm.shll(asIntReg(dst), crb.asIntConst(src) & 31); - break; - case ISHR: - masm.sarl(asIntReg(dst), crb.asIntConst(src) & 31); - break; - case IUSHR: - masm.shrl(asIntReg(dst), crb.asIntConst(src) & 31); - break; - case IROL: - masm.roll(asIntReg(dst), crb.asIntConst(src) & 31); - break; - case IROR: - masm.rorl(asIntReg(dst), crb.asIntConst(src) & 31); - break; - - case LADD: - masm.addq(asLongReg(dst), crb.asIntConst(src)); - break; - case LSUB: - masm.subq(asLongReg(dst), crb.asIntConst(src)); - break; - case LAND: - masm.andq(asLongReg(dst), crb.asIntConst(src)); - break; - case LOR: - masm.orq(asLongReg(dst), crb.asIntConst(src)); - break; - case LXOR: - masm.xorq(asLongReg(dst), crb.asIntConst(src)); - break; - case LSHL: - masm.shlq(asLongReg(dst), crb.asIntConst(src) & 63); - break; - case LSHR: - masm.sarq(asLongReg(dst), crb.asIntConst(src) & 63); - break; - case LUSHR: - masm.shrq(asLongReg(dst), crb.asIntConst(src) & 63); - break; - case LROL: - masm.rolq(asLongReg(dst), crb.asIntConst(src) & 31); - break; - case LROR: - masm.rorq(asLongReg(dst), crb.asIntConst(src) & 31); - break; - - case FADD: - masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src)); - break; - case FSUB: - masm.subss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src)); - break; - case FMUL: - masm.mulss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src)); - break; - case FAND: - masm.andps(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src, 16)); - break; - case FOR: - masm.orps(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src, 16)); - break; - case FXOR: - masm.xorps(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src, 16)); - break; - case FDIV: - masm.divss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src)); - break; - - case DADD: - masm.addsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src)); - break; - case DSUB: - masm.subsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src)); - break; - case DMUL: - masm.mulsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src)); - break; - case DDIV: - masm.divsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src)); - break; - case DAND: - masm.andpd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src, 16)); - break; - case DOR: - masm.orpd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src, 16)); - break; - case DXOR: - masm.xorpd(asDoubleReg(dst), (AMD64Address) crb.asDoubleConstRef(src, 16)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isStackSlot(src)) { - - switch (opcode) { - case IADD: - masm.addl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case ISUB: - masm.subl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case IAND: - masm.andl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case IMUL: - masm.imull(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case IOR: - masm.orl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case IXOR: - masm.xorl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - - case LADD: - masm.addq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case LSUB: - masm.subq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case LMUL: - masm.imulq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case LAND: - masm.andq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case LOR: - masm.orq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case LXOR: - masm.xorq(asLongReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - - case FADD: - masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - case FSUB: - masm.subss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - case FMUL: - masm.mulss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - case FDIV: - masm.divss(asFloatReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - - case DADD: - masm.addsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - case DSUB: - masm.subsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - case DMUL: - masm.mulsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - case DDIV: - masm.divsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - - case SQRT: - masm.sqrtsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - - case B2I: - masm.movsbl(asIntReg(dst), (AMD64Address) crb.asByteAddr(src)); - break; - case S2I: - masm.movswl(asIntReg(dst), (AMD64Address) crb.asShortAddr(src)); - break; - case B2L: - masm.movsbq(asLongReg(dst), (AMD64Address) crb.asByteAddr(src)); - break; - case S2L: - masm.movswq(asLongReg(dst), (AMD64Address) crb.asShortAddr(src)); - break; - case I2L: - masm.movslq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case F2D: - masm.cvtss2sd(asDoubleReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - case D2F: - masm.cvtsd2ss(asFloatReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - case I2F: - masm.cvtsi2ssl(asFloatReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case I2D: - masm.cvtsi2sdl(asDoubleReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case L2F: - masm.cvtsi2ssq(asFloatReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case L2D: - masm.cvtsi2sdq(asDoubleReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case F2I: - masm.cvttss2sil(asIntReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - case D2I: - masm.cvttsd2sil(asIntReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - case F2L: - masm.cvttss2siq(asLongReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - case D2L: - masm.cvttsd2siq(asLongReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - case MOV_I2F: - masm.movss(asFloatReg(dst), (AMD64Address) crb.asIntAddr(src)); - break; - case MOV_L2D: - masm.movsd(asDoubleReg(dst), (AMD64Address) crb.asLongAddr(src)); - break; - case MOV_F2I: - masm.movl(asIntReg(dst), (AMD64Address) crb.asFloatAddr(src)); - break; - case MOV_D2L: - masm.movq(asLongReg(dst), (AMD64Address) crb.asDoubleAddr(src)); - break; - - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else { - switch (opcode) { - case IADD: - masm.addl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case ISUB: - masm.subl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case IAND: - masm.andl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case IMUL: - masm.imull(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case IOR: - masm.orl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case IXOR: - masm.xorl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - - case LADD: - masm.addq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case LSUB: - masm.subq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case LMUL: - masm.imulq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case LAND: - masm.andq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case LOR: - masm.orq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case LXOR: - masm.xorq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - - case FADD: - masm.addss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case FSUB: - masm.subss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case FMUL: - masm.mulss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case FDIV: - masm.divss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - - case DADD: - masm.addsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case DSUB: - masm.subsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case DMUL: - masm.mulsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case DDIV: - masm.divsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - - case SQRT: - masm.sqrtsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - - case B2I: - masm.movsbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case S2I: - masm.movswl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case B2L: - masm.movsbq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case S2L: - masm.movswq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case I2L: - masm.movslq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case F2D: - masm.cvtss2sd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case D2F: - masm.cvtsd2ss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case I2F: - masm.cvtsi2ssl(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case I2D: - masm.cvtsi2sdl(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case L2F: - masm.cvtsi2ssq(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case L2D: - masm.cvtsi2sdq(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case F2I: - masm.cvttss2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case D2I: - masm.cvttsd2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case F2L: - masm.cvttss2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case D2L: - masm.cvttsd2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case MOV_I2F: - masm.movss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case MOV_L2D: - masm.movsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case MOV_F2I: - masm.movl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case MOV_D2L: - masm.movq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case MOV_B2UI: - masm.movzbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - case MOV_B2UL: - masm.movzbl(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); - break; - - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - if (info != null) { - assert exceptionOffset != -1; - crb.recordImplicitException(exceptionOffset, info); - } - } - - private static void verifyKind(AMD64Arithmetic opcode, Value result, Value x, Value y) { - assert (opcode.name().startsWith("I") && result.getKind().getStackKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || - (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long) || - (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || - (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double) || - (opcode.name().matches(".U?SH.") && result.getKind() == x.getKind() && y.getKind() == Kind.Int && (isConstant(y) || asRegister(y).equals(AMD64.rcx))); - } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryCommutativeOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryCommutativeOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64BinaryCommutativeOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryCommutativeOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public AMD64BinaryCommutativeOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AllocatableValue input; + if (sameRegister(result, y)) { + input = x; + } else { + AMD64Move.move(crb, masm, result, x); + input = y; + } + + if (isRegister(input)) { + opcode.emit(masm, size, asRegister(result), asRegister(input)); + } else { + assert isStackSlot(input); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input)); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConstOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConstOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64BinaryConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + protected JavaConstant y; + + public AMD64BinaryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + this(opcode.getMIOpcode(size, NumUtil.isByte(y.asLong())), size, result, x, y); + } + + public AMD64BinaryConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + assert NumUtil.is32bit(y.asLong()); + opcode.emit(masm, size, asRegister(result), (int) y.asLong()); + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryMemoryOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryMemoryOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.asm.*; + +public class AMD64BinaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryMemoryOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({COMPOSITE}) protected AMD64AddressValue y; + + @State protected LIRFrameState state; + + public AMD64BinaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(result), y.toAddress()); + } + + @Override + public void verify() { + super.verify(); + assert differentRegisters(result, y) || sameRegister(x, y); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64BinaryOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({REG, STACK}) protected AllocatableValue y; + + public AMD64BinaryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(result), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y)); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryPatchOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryPatchOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64BinaryPatchOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryPatchOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + protected JavaConstant y; + + private final int alignment; + + public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + this(opcode, size, result, x, y, y.getKind().getByteCount()); + } + + public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.alignment = alignment; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.amd64; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public final class AMD64BitManipulationOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BitManipulationOp.class); - - public enum IntrinsicOpcode { - IPOPCNT, - LPOPCNT, - IBSR, - LBSR, - BSF, - ILZCNT, - LLZCNT, - ITZCNT, - LTZCNT - } - - @Opcode private final IntrinsicOpcode opcode; - @Def protected AllocatableValue result; - @Use({OperandFlag.REG, OperandFlag.STACK}) protected AllocatableValue input; - - public AMD64BitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input) { - super(TYPE); - this.opcode = opcode; - this.result = result; - this.input = input; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - Register dst = ValueUtil.asIntReg(result); - if (ValueUtil.isRegister(input)) { - Register src = ValueUtil.asRegister(input); - switch (opcode) { - case IPOPCNT: - masm.popcntl(dst, src); - break; - case LPOPCNT: - masm.popcntq(dst, src); - break; - case BSF: - masm.bsfq(dst, src); - break; - case IBSR: - masm.bsrl(dst, src); - break; - case LBSR: - masm.bsrq(dst, src); - break; - case ILZCNT: - masm.lzcntl(dst, src); - break; - case LLZCNT: - masm.lzcntq(dst, src); - break; - case ITZCNT: - masm.tzcntl(dst, src); - break; - case LTZCNT: - masm.tzcntq(dst, src); - break; - } - } else { - AMD64Address src = (AMD64Address) crb.asAddress(input); - switch (opcode) { - case IPOPCNT: - masm.popcntl(dst, src); - break; - case LPOPCNT: - masm.popcntq(dst, src); - break; - case BSF: - masm.bsfq(dst, src); - break; - case IBSR: - masm.bsrl(dst, src); - break; - case LBSR: - masm.bsrq(dst, src); - break; - case ILZCNT: - masm.lzcntl(dst, src); - break; - case LLZCNT: - masm.lzcntq(dst, src); - break; - case ITZCNT: - masm.tzcntl(dst, src); - break; - case LTZCNT: - masm.tzcntq(dst, src); - break; - } - } - } - -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ClearRegisterOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ClearRegisterOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64ClearRegisterOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ClearRegisterOp.class); + + @Opcode private final AMD64RMOp op; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + + public AMD64ClearRegisterOp(OperandSize size, AllocatableValue result) { + super(TYPE); + this.op = XOR.getRMOpcode(size); + this.size = size; + this.result = result; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + op.emit(masm, size, asRegister(result), asRegister(result)); + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.AMD64Move.MemOp; -import com.oracle.graal.lir.asm.*; - -public enum AMD64Compare { - BCMP, - SCMP, - ICMP, - LCMP, - ACMP, - FCMP, - DCMP; - - public static final class CompareOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareOp.class); - @Opcode private final AMD64Compare opcode; - @Use({REG}) protected Value x; - @Use({REG, STACK, CONST}) protected Value y; - - public CompareOp(AMD64Compare opcode, Value x, Value y) { - super(TYPE); - this.opcode = opcode; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - emit(crb, masm, opcode, x, y); - } - - @Override - public void verify() { - super.verify(); - assert (name().startsWith("B") && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || - (name().startsWith("S") && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || - (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind() == Kind.Int) || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) || - (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) || - (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double) : String.format( - "%s(%s, %s)", opcode, x, y); - } - } - - public static final class CompareMemoryOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareMemoryOp.class); - @Opcode private final AMD64Compare opcode; - @Use({REG, CONST}) protected Value y; - - /** - * Compare memory, constant or register, memory. - */ - public CompareMemoryOp(AMD64Compare opcode, Kind kind, AMD64AddressValue address, Value y, LIRFrameState state) { - super(TYPE, kind, address, state); - this.opcode = opcode; - this.y = y; - } - - @Override - protected void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (isRegister(y)) { - switch (opcode) { - case BCMP: - masm.cmpb(asIntReg(y), address.toAddress()); - break; - case SCMP: - masm.cmpw(asIntReg(y), address.toAddress()); - break; - case ICMP: - masm.cmpl(asIntReg(y), address.toAddress()); - break; - case LCMP: - masm.cmpq(asLongReg(y), address.toAddress()); - break; - case ACMP: - masm.cmpptr(asObjectReg(y), address.toAddress()); - break; - case FCMP: - masm.ucomiss(asFloatReg(y), address.toAddress()); - break; - case DCMP: - masm.ucomisd(asDoubleReg(y), address.toAddress()); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isConstant(y)) { - switch (opcode) { - case BCMP: - masm.cmpb(address.toAddress(), crb.asIntConst(y)); - break; - case SCMP: - masm.cmpw(address.toAddress(), crb.asIntConst(y)); - break; - case ICMP: - masm.cmpl(address.toAddress(), crb.asIntConst(y)); - break; - case LCMP: - if (NumUtil.isInt(crb.asLongConst(y))) { - masm.cmpq(address.toAddress(), (int) crb.asLongConst(y)); - } else { - throw GraalInternalError.shouldNotReachHere(); - } - break; - case ACMP: - if (asConstant(y).isNull()) { - masm.cmpq(address.toAddress(), 0); - } else { - throw GraalInternalError.shouldNotReachHere(); - } - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - - @Override - public void verify() { - super.verify(); - assert y instanceof Variable || y instanceof JavaConstant; - assert kind != Kind.Long || !(y instanceof JavaConstant) || NumUtil.isInt(((JavaConstant) y).asLong()); - } - } - - public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Compare opcode, Value x, Value y) { - if (isRegister(x) && isRegister(y)) { - switch (opcode) { - case BCMP: - masm.cmpb(asIntReg(x), asIntReg(y)); - break; - case SCMP: - masm.cmpw(asIntReg(x), asIntReg(y)); - break; - case ICMP: - masm.cmpl(asIntReg(x), asIntReg(y)); - break; - case LCMP: - masm.cmpq(asLongReg(x), asLongReg(y)); - break; - case ACMP: - masm.cmpptr(asObjectReg(x), asObjectReg(y)); - break; - case FCMP: - masm.ucomiss(asFloatReg(x), asFloatReg(y)); - break; - case DCMP: - masm.ucomisd(asDoubleReg(x), asDoubleReg(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isRegister(x) && isConstant(y)) { - boolean isZero = ((JavaConstant) y).isDefaultForKind(); - switch (opcode) { - case BCMP: - if (isZero) { - masm.testl(asIntReg(x), asIntReg(x)); - } else { - masm.cmpb(asIntReg(x), crb.asIntConst(y)); - } - break; - case SCMP: - if (isZero) { - masm.testl(asIntReg(x), asIntReg(x)); - } else { - masm.cmpw(asIntReg(x), crb.asIntConst(y)); - } - break; - case ICMP: - if (isZero) { - masm.testl(asIntReg(x), asIntReg(x)); - } else { - masm.cmpl(asIntReg(x), crb.asIntConst(y)); - } - break; - case LCMP: - if (isZero) { - masm.testq(asLongReg(x), asLongReg(x)); - } else { - masm.cmpq(asLongReg(x), crb.asIntConst(y)); - } - break; - case ACMP: - if (isZero) { - masm.testq(asObjectReg(x), asObjectReg(x)); - break; - } else { - throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons"); - } - case FCMP: - masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y)); - break; - case DCMP: - masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isRegister(x) && isStackSlot(y)) { - switch (opcode) { - case BCMP: - masm.cmpb(asIntReg(x), (AMD64Address) crb.asByteAddr(y)); - break; - case SCMP: - masm.cmpw(asIntReg(x), (AMD64Address) crb.asShortAddr(y)); - break; - case ICMP: - masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y)); - break; - case LCMP: - masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y)); - break; - case ACMP: - masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y)); - break; - case FCMP: - masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y)); - break; - case DCMP: - masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareConstOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareConstOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64CompareConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Use({REG, STACK}) protected AllocatableValue x; + protected JavaConstant y; + + public AMD64CompareConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, JavaConstant y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + assert NumUtil.is32bit(y.asLong()); + if (isRegister(x)) { + opcode.emit(masm, size, asRegister(x), (int) y.asLong()); + } else { + assert isStackSlot(x); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), (int) y.asLong()); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryConstOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryConstOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.asm.*; + +public class AMD64CompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareMemoryConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Use({COMPOSITE}) protected AMD64AddressValue x; + protected JavaConstant y; + + @State protected LIRFrameState state; + + public AMD64CompareMemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, JavaConstant y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + assert NumUtil.is32bit(y.asLong()); + opcode.emit(masm, size, x.toAddress(), (int) y.asLong()); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.asm.*; + +public class AMD64CompareMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareMemoryOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + @Use({COMPOSITE}) protected AMD64AddressValue y; + + @State protected LIRFrameState state; + + public AMD64CompareMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(x), y.toAddress()); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64CompareOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public AMD64CompareOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(x), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y)); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulConstOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulConstOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64MulConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MulConstOp.class); + + @Opcode private final AMD64RMIOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + protected JavaConstant y; + + public AMD64MulConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + assert NumUtil.isInt(y.asLong()); + int imm = (int) y.asLong(); + if (isRegister(x)) { + opcode.emit(masm, size, asRegister(result), asRegister(x), imm); + } else { + assert isStackSlot(x); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), imm); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64MulDivOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MulDivOp.class); + + @Opcode private final AMD64MOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue highResult; + @Def({REG}) protected AllocatableValue lowResult; + + @Use({REG, ILLEGAL}) protected AllocatableValue highX; + @Use({REG}) protected AllocatableValue lowX; + + @Use({REG, STACK}) protected AllocatableValue y; + + @State protected LIRFrameState state; + + public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue x, AllocatableValue y) { + this(opcode, size, resultKind, Value.ILLEGAL, x, y, null); + } + + public AMD64MulDivOp(AMD64MOp opcode, OperandSize size, LIRKind resultKind, AllocatableValue highX, AllocatableValue lowX, AllocatableValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.highResult = AMD64.rdx.asValue(resultKind); + this.lowResult = AMD64.rax.asValue(resultKind); + + this.highX = highX; + this.lowX = lowX; + + this.y = y; + + this.state = state; + } + + public AllocatableValue getHighResult() { + return highResult; + } + + public AllocatableValue getLowResult() { + return lowResult; + } + + public AllocatableValue getQuotient() { + return lowResult; + } + + public AllocatableValue getRemainder() { + return highResult; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(y)); + } + } + + @Override + public void verify() { + assert asRegister(highResult).equals(AMD64.rdx); + assert asRegister(lowResult).equals(AMD64.rax); + + assert asRegister(lowX).equals(AMD64.rax); + if (opcode == DIV || opcode == IDIV) { + assert asRegister(highX).equals(AMD64.rdx); + } else if (opcode == MUL || opcode == IMUL) { + assert isIllegal(highX); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegStackConstOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegStackConstOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64RegStackConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64RegStackConstOp.class); + + @Opcode private final AMD64RMIOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + protected JavaConstant y; + + public AMD64RegStackConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + assert NumUtil.is32bit(y.asLong()); + if (isRegister(x)) { + opcode.emit(masm, size, asRegister(result), asRegister(x), (int) y.asLong()); + } else { + assert isStackSlot(x); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), (int) y.asLong()); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64ShiftOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ShiftOp.class); + + @Opcode private final AMD64MOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({REG}) protected AllocatableValue y; + + public AMD64ShiftOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + opcode.emit(masm, size, asRegister(result)); + } + + @Override + public void verify() { + assert asRegister(y).equals(AMD64.rcx); + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SignExtendOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SignExtendOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +@Opcode("CDQ") +public class AMD64SignExtendOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64SignExtendOp.class); + + private final OperandSize size; + + @Def({REG}) protected AllocatableValue highResult; + @Def({REG}) protected AllocatableValue lowResult; + + @Use({REG}) protected AllocatableValue input; + + public AMD64SignExtendOp(OperandSize size, LIRKind resultKind, AllocatableValue input) { + super(TYPE); + this.size = size; + + this.highResult = AMD64.rdx.asValue(resultKind); + this.lowResult = AMD64.rax.asValue(resultKind); + this.input = input; + } + + public AllocatableValue getHighResult() { + return highResult; + } + + public AllocatableValue getLowResult() { + return lowResult; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (size == DWORD) { + masm.cdql(); + } else { + assert size == QWORD; + masm.cdqq(); + } + } + + @Override + public void verify() { + assert asRegister(highResult).equals(AMD64.rdx); + assert asRegister(lowResult).equals(AMD64.rax); + assert asRegister(input).equals(AMD64.rax); + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.AMD64Move.MemOp; -import com.oracle.graal.lir.asm.*; - -public final class AMD64TestMemoryOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64TestMemoryOp.class); - - @Use({REG, CONST}) protected Value y; - - public AMD64TestMemoryOp(Kind kind, AMD64AddressValue x, Value y, LIRFrameState state) { - super(TYPE, kind, x, state); - this.y = y; - this.state = state; - } - - @Override - public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (isRegister(y)) { - switch (kind) { - case Int: - masm.testl(asIntReg(y), address.toAddress()); - break; - case Long: - masm.testq(asLongReg(y), address.toAddress()); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isConstant(y)) { - switch (kind) { - case Int: - masm.testl(address.toAddress(), crb.asIntConst(y)); - break; - case Long: - masm.testq(address.toAddress(), crb.asIntConst(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - - @Override - public void verify() { - super.verify(); - assert (kind == Kind.Int || kind == Kind.Long) && kind == y.getKind() : address + " " + y; - } -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java Tue Mar 17 12:05:11 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public final class AMD64TestOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64TestOp.class); - - @Use({REG}) protected Value x; - @Use({REG, STACK, CONST}) protected Value y; - - public AMD64TestOp(Value x, Value y) { - super(TYPE); - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - emit(crb, masm, x, y); - } - - @Override - public void verify() { - super.verify(); - assert (x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || (x.getKind() == Kind.Long && y.getKind() == Kind.Long) : x + " " + y; - } - - public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value x, Value y) { - if (isRegister(y)) { - switch (x.getKind()) { - case Int: - masm.testl(asIntReg(x), asIntReg(y)); - break; - case Long: - masm.testq(asLongReg(x), asLongReg(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isConstant(y)) { - switch (x.getKind()) { - case Int: - masm.testl(asIntReg(x), crb.asIntConst(y)); - break; - case Long: - masm.testq(asLongReg(x), crb.asIntConst(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else { - switch (x.getKind()) { - case Int: - masm.testl(asIntReg(x), (AMD64Address) crb.asIntAddr(y)); - break; - case Long: - masm.testq(asLongReg(x), (AMD64Address) crb.asLongAddr(y)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } -} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64UnaryMOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryMOp.class); + + @Opcode private final AMD64MOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue value; + + public AMD64UnaryMOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, value); + opcode.emit(masm, size, asRegister(result)); + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMROp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMROp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64UnaryMROp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryMROp.class); + + @Opcode private final AMD64MROp opcode; + private final OperandSize size; + + @Def({REG, STACK}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue value; + + public AMD64UnaryMROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(result)) { + opcode.emit(masm, size, asRegister(result), asRegister(value)); + } else { + assert isStackSlot(result); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value)); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMemoryOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMemoryOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.asm.*; + +public class AMD64UnaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryMemoryOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE}) protected AMD64AddressValue input; + + @State protected LIRFrameState state; + + public AMD64UnaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.input = input; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(result), input.toAddress()); + } + + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryRMOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryRMOp.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64UnaryRMOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryRMOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue value; + + public AMD64UnaryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(value)) { + opcode.emit(masm, size, asRegister(result), asRegister(value)); + } else { + assert isStackSlot(value); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value)); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -162,7 +162,7 @@ compilationResult.recordInfopoint(pos, debugInfo, reason); } - public void recordInlineDataInCode(JavaConstant data) { + public void recordInlineDataInCode(Constant data) { assert data != null; int pos = asm.position(); Debug.log("Inline data in code: pos = %d, data = %s", pos, data); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -177,13 +177,14 @@ return res.getFrameMapBuilder().getRegisterConfig().getReturnRegister((Kind) kind.getPlatformKind()).asValue(kind); } - public void append(LIRInstruction op) { + public I append(I op) { if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { TTY.println(op.toStringWithIdPrefix()); TTY.println(); } assert LIRVerifier.verify(op); res.getLIR().getLIRforBlock(currentBlock).add(op); + return op; } public boolean hasBlockEnd(AbstractBlockBase block) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -159,7 +159,7 @@ */ AllocatableValue resultOperandFor(LIRKind kind); - void append(LIRInstruction op); + I append(I op); void emitJump(LabelRef label); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -28,7 +28,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodeinfo.*; @@ -42,7 +41,6 @@ public final class ConstantNode extends FloatingNode implements LIRLowerable { public static final NodeClass TYPE = NodeClass.create(ConstantNode.class); - private static final DebugMetric ConstantNodes = Debug.metric("ConstantNodes"); protected final Constant value; @@ -60,7 +58,6 @@ super(TYPE, stamp); assert stamp != null && isCompatible(value, stamp); this.value = value; - ConstantNodes.increment(); } private static boolean isCompatible(Constant value, Stamp stamp) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -107,7 +107,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -154,7 +154,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -76,7 +76,7 @@ } else { int index = locationIdentities.indexOf(locationIdentity); if (index == -1) { - index = locationIdentities.indexOf(ANY_LOCATION); + index = locationIdentities.indexOf(any()); } assert index != -1; return (MemoryNode) nodes.get(index); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -44,6 +44,6 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -246,7 +246,7 @@ protected static boolean livesLonger(ValueNode after, ValueNode value, NodeMappableLIRBuilder builder) { for (Node usage : value.usages()) { - if (usage != after && usage instanceof ValueNode && builder.hasOperand(((ValueNode) usage))) { + if (usage != after && usage instanceof ValueNode && builder.hasOperand(usage)) { return true; } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Mar 17 12:05:51 2015 +0100 @@ -24,9 +24,11 @@ import java.util.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; public final class Block extends AbstractBlockBase { @@ -39,6 +41,8 @@ protected Block postdominator; protected Block distancedDominatorCache; + private LocationSet killLocations; + private LocationSet killLocationsBetweenThisAndDominator; protected Block(AbstractBeginNode node) { this.beginNode = node; @@ -189,4 +193,85 @@ } return result; } + + public boolean canKill(LocationIdentity location) { + if (location.isImmutable()) { + return false; + } + return getKillLocations().contains(location); + } + + public LocationSet getKillLocations() { + if (killLocations == null) { + killLocations = calcKillLocations(); + } + return killLocations; + } + + private LocationSet calcKillLocations() { + LocationSet result = new LocationSet(); + for (FixedNode node : this.getNodes()) { + if (node instanceof MemoryCheckpoint.Single) { + LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); + result.add(identity); + } else if (node instanceof MemoryCheckpoint.Multi) { + for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) { + result.add(identity); + } + } + if (result.isAny()) { + break; + } + } + return result; + } + + public boolean canKillBetweenThisAndDominator(LocationIdentity location) { + if (location.isImmutable()) { + return false; + } + return this.getKillLocationsBetweenThisAndDominator().contains(location); + } + + private LocationSet getKillLocationsBetweenThisAndDominator() { + if (this.killLocationsBetweenThisAndDominator == null) { + LocationSet dominatorResult = new LocationSet(); + Block stopBlock = getDominator(); + for (Block b : this.getPredecessors()) { + if (b != stopBlock && (!this.isLoopHeader() || b.getLoopDepth() < this.getLoopDepth())) { + dominatorResult.addAll(b.getKillLocations()); + if (dominatorResult.isAny()) { + break; + } + b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock); + if (dominatorResult.isAny()) { + break; + } + } + } + this.killLocationsBetweenThisAndDominator = dominatorResult; + } + return this.killLocationsBetweenThisAndDominator; + } + + private void calcKillLocationsBetweenThisAndTarget(LocationSet result, Block stopBlock) { + assert AbstractControlFlowGraph.dominates(stopBlock, this); + if (stopBlock == this || result.isAny()) { + // We reached the stop block => nothing to do. + return; + } else { + if (stopBlock == this.getDominator()) { + result.addAll(this.getKillLocationsBetweenThisAndDominator()); + } else { + // Divide and conquer: Aggregate kill locations from this to the dominator and then + // from the dominator onwards. + calcKillLocationsBetweenThisAndTarget(result, this.getDominator()); + result.addAll(this.getDominator().getKillLocations()); + if (result.isAny()) { + return; + } + this.getDominator().calcKillLocationsBetweenThisAndTarget(result, stopBlock); + } + } + } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Tue Mar 17 12:05:51 2015 +0100 @@ -40,7 +40,7 @@ public final StructuredGraph graph; - private final NodeMap nodeToBlock; + private NodeMap nodeToBlock; private List reversePostOrder; private List> loops; @@ -365,4 +365,8 @@ } return iterA; } + + public void setNodeToBlock(NodeMap nodeMap) { + this.nodeToBlock = nodeMap; + } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java Tue Mar 17 12:05:51 2015 +0100 @@ -22,10 +22,13 @@ */ package com.oracle.graal.nodes.cfg; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.nodes.*; -public class HIRLoop extends Loop { +public final class HIRLoop extends Loop { + + private LocationSet killLocations; protected HIRLoop(Loop parent, int index, Block header) { super(parent, index, header); @@ -35,4 +38,29 @@ public long numBackedges() { return ((LoopBeginNode) getHeader().getBeginNode()).loopEnds().count(); } + + private LocationSet getKillLocations() { + if (killLocations == null) { + killLocations = new LocationSet(); + for (Block b : this.getBlocks()) { + if (b.getLoop() == this) { + killLocations.addAll(b.getKillLocations()); + if (killLocations.isAny()) { + break; + } + } + } + } + for (Loop child : this.getChildren()) { + if (killLocations.isAny()) { + break; + } + killLocations.addAll(((HIRLoop) child).getKillLocations()); + } + return killLocations; + } + + public boolean canKill(LocationIdentity location) { + return getKillLocations().contains(location); + } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/LocationSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/LocationSet.java Tue Mar 17 12:05:51 2015 +0100 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.cfg; + +import java.util.*; + +import com.oracle.graal.api.meta.*; + +public class LocationSet { + private LocationIdentity firstLocation; + private List list; + + public LocationSet() { + list = null; + } + + public LocationSet(LocationSet other) { + this.firstLocation = other.firstLocation; + if (other.list != null && other.list.size() > 0) { + list = new ArrayList<>(other.list); + } + } + + private void initList() { + if (list == null) { + list = new ArrayList<>(4); + } + } + + public boolean isEmpty() { + return firstLocation == null; + } + + public boolean isAny() { + return firstLocation != null && firstLocation.isAny(); + } + + public void add(LocationIdentity location) { + if (this.isAny()) { + return; + } else if (location.isAny()) { + firstLocation = location; + list = null; + } else if (location.isImmutable()) { + return; + } else { + assert location.isMutable() && location.isSingle(); + if (firstLocation == null) { + firstLocation = location; + } else if (location.equals(firstLocation)) { + return; + } else { + initList(); + for (int i = 0; i < list.size(); ++i) { + LocationIdentity value = list.get(i); + if (location.equals(value)) { + return; + } + } + list.add(location); + } + } + } + + public void addAll(LocationSet other) { + if (other.firstLocation != null) { + add(other.firstLocation); + } + List otherList = other.list; + if (otherList != null) { + for (LocationIdentity l : otherList) { + add(l); + } + } + } + + public boolean contains(LocationIdentity locationIdentity) { + assert locationIdentity.isSingle(); + assert locationIdentity.isMutable(); + if (LocationIdentity.any().equals(firstLocation)) { + return true; + } + if (locationIdentity.equals(firstLocation)) { + return true; + } + if (list != null) { + for (int i = 0; i < list.size(); ++i) { + LocationIdentity value = list.get(i); + if (locationIdentity.equals(value)) { + return true; + } + } + } + return false; + } + + public List getCopyAsList() { + ArrayList result = new ArrayList<>(); + if (firstLocation != null) { + result.add(firstLocation); + } + if (list != null) { + result.addAll(list); + } + return result; + } + + @Override + public String toString() { + if (this.isAny()) { + return "ANY"; + } else if (this.isEmpty()) { + return "EMPTY"; + } else { + List copyAsList = getCopyAsList(); + return Arrays.toString(copyAsList.toArray(new LocationIdentity[0])); + } + } +} diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -59,7 +59,7 @@ } public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } public void lower(LoweringTool tool) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -22,7 +22,6 @@ */ package com.oracle.graal.nodes.extended; -import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; @@ -56,6 +55,6 @@ * an attached write barrier with pre-semantics can not also float. */ public boolean canFloat() { - return !location().getLocationIdentity().equals(LocationIdentity.ANY_LOCATION) && getBarrierType() == BarrierType.NONE; + return location().getLocationIdentity().isSingle() && getBarrierType() == BarrierType.NONE; } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -53,10 +53,6 @@ this.foreignCalls = foreignCalls; } - public ForeignCallNode(ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, List arguments) { - this(foreignCalls, descriptor, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())), arguments); - } - public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List arguments) { super(TYPE, stamp); this.arguments = new NodeInputList<>(this, arguments); @@ -64,15 +60,15 @@ this.foreignCalls = foreignCalls; } - protected ForeignCallNode(NodeClass c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) { - super(c, stamp); + public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) { + super(TYPE, stamp); this.arguments = new NodeInputList<>(this); this.descriptor = descriptor; this.foreignCalls = foreignCalls; } - public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) { - super(TYPE, stamp); + protected ForeignCallNode(NodeClass c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) { + super(c, stamp); this.arguments = new NodeInputList<>(this); this.descriptor = descriptor; this.foreignCalls = foreignCalls; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -45,7 +45,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Tue Mar 17 12:05:51 2015 +0100 @@ -39,7 +39,7 @@ /** * This method is used to determine which memory location is killed by this node. Returning - * the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory locations. + * the special value {@link LocationIdentity#any()} will kill all memory locations. * * @return the identity of the location killed by this node. */ @@ -51,7 +51,7 @@ /** * This method is used to determine which set of memory locations is killed by this node. - * Returning the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory + * Returning the special value {@link LocationIdentity#any()} will kill all memory * locations. * * @return the identities of all locations killed by this node. diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -28,17 +28,22 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; @NodeInfo -public final class UnboxNode extends UnaryNode implements Virtualizable, Lowerable { +public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary { public static final NodeClass TYPE = NodeClass.create(UnboxNode.class); + @Input protected ValueNode value; protected final Kind boxingKind; + public ValueNode getValue() { + return value; + } + protected UnboxNode(ValueNode value, Kind boxingKind) { - super(TYPE, StampFactory.forKind(boxingKind.getStackKind()), value); + super(TYPE, StampFactory.forKind(boxingKind.getStackKind())); + this.value = value; this.boxingKind = boxingKind; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -66,7 +66,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (this.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION) && offset().isConstant()) { + if (this.getLocationIdentity().isAny() && offset().isConstant()) { long constantOffset = offset().asJavaConstant().asLong(); // Try to canonicalize to a field access. @@ -82,7 +82,7 @@ } } } - if (this.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION)) { + if (this.getLocationIdentity().isAny()) { ResolvedJavaType receiverType = StampTool.typeOrNull(object()); // Try to build a better location identity. if (receiverType != null && receiverType.isArray()) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -44,7 +44,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -42,6 +42,15 @@ @Input ValueNode object; @Input ValueNode mirror; + public static LogicNode create(ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object) { + LogicNode synonym = findSynonym(constantReflection, object, mirror); + if (synonym != null) { + return synonym; + } + return new InstanceOfDynamicNode(mirror, object); + + } + public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) { super(TYPE); this.mirror = mirror; @@ -56,9 +65,9 @@ tool.getLowerer().lower(this, tool); } - public LogicNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forMirror) { + private static LogicNode findSynonym(ConstantReflectionProvider constantReflection, ValueNode forObject, ValueNode forMirror) { if (forMirror.isConstant()) { - ResolvedJavaType t = tool.getConstantReflection().asJavaType(forMirror.asConstant()); + ResolvedJavaType t = constantReflection.asJavaType(forMirror.asConstant()); if (t != null) { if (t.isPrimitive()) { return LogicConstantNode.contradiction(); @@ -67,7 +76,15 @@ } } } - return this; + return null; + } + + public LogicNode canonical(CanonicalizerTool tool, ValueNode forObject, ValueNode forMirror) { + LogicNode res = findSynonym(tool.getConstantReflection(), forObject, forMirror); + if (res == null) { + res = this; + } + return res; } public ValueNode object() { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -43,7 +43,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -58,7 +58,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java Tue Mar 17 12:05:51 2015 +0100 @@ -28,6 +28,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; @@ -71,5 +72,5 @@ Value[] visitInvokeArguments(CallingConvention cc, Collection arguments); - void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap); + void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java Tue Mar 17 12:05:51 2015 +0100 @@ -24,13 +24,14 @@ package com.oracle.graal.nodes.spi; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; public interface NodeMappableLIRBuilder { - Value operand(ValueNode object); + Value operand(Node object); - boolean hasOperand(ValueNode object); + boolean hasOperand(Node object); Value setResult(ValueNode x, Value operand); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Tue Mar 17 12:05:51 2015 +0100 @@ -33,6 +33,8 @@ * Interface for managing replacements. */ public interface Replacements { + // Disabled until bug in support for this is fixed. + boolean SELF_RECURSIVE_INTRINSICS_ENABLED = false; /** * Gets the snippet graph derived from a given method. diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -24,7 +24,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.Graph.NodeEventListener; @@ -254,30 +253,24 @@ } if (nodeClass.isCanonicalizable()) { METRIC_CANONICALIZATION_CONSIDERED_NODES.increment(); - try (Scope s = Debug.scope("CanonicalizeNode", node)) { - Node canonical; - try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) { - canonical = ((Canonicalizable) node).canonical(tool); - if (canonical == node && nodeClass.isCommutative()) { - canonical = ((BinaryCommutative) node).maybeCommuteInputs(); - } - } - if (performReplacement(node, canonical)) { - return true; + Node canonical; + try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) { + canonical = ((Canonicalizable) node).canonical(tool); + if (canonical == node && nodeClass.isCommutative()) { + canonical = ((BinaryCommutative) node).maybeCommuteInputs(); } } catch (Throwable e) { throw Debug.handle(e); } + if (performReplacement(node, canonical)) { + return true; + } } if (nodeClass.isSimplifiable() && simplify) { Debug.log(3, "Canonicalizer: simplifying %s", node); METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment(); - try (Scope s = Debug.scope("SimplifyNode", node)) { - node.simplify(tool); - } catch (Throwable e) { - throw Debug.handle(e); - } + node.simplify(tool); return node.isDeleted(); } return false; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -29,10 +29,12 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.graph.Graph.NodeEventScope; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -56,7 +58,7 @@ public MemoryMapImpl(StartNode start) { lastMemorySnapshot = CollectionsFactory.newMap(); - lastMemorySnapshot.put(ANY_LOCATION, start); + lastMemorySnapshot.put(any(), start); } public MemoryMapImpl() { @@ -71,7 +73,7 @@ } else { lastLocationAccess = lastMemorySnapshot.get(locationIdentity); if (lastLocationAccess == null) { - lastLocationAccess = lastMemorySnapshot.get(ANY_LOCATION); + lastLocationAccess = lastMemorySnapshot.get(any()); assert lastLocationAccess != null; } return lastLocationAccess; @@ -125,10 +127,56 @@ return set; } + protected void processNode(FixedNode node, Set currentState) { + if (node instanceof MemoryCheckpoint.Single) { + currentState.add(((MemoryCheckpoint.Single) node).getLocationIdentity()); + } else if (node instanceof MemoryCheckpoint.Multi) { + for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) { + currentState.add(identity); + } + } + } + + protected void processBlock(Block b, Set currentState) { + for (FixedNode n : b.getNodes()) { + processNode(n, currentState); + } + } + + private Set processLoop(HIRLoop loop, Map> modifiedInLoops) { + LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode(); + Set result = modifiedInLoops.get(loopBegin); + if (result != null) { + return result; + } + + result = CollectionsFactory.newSet(); + for (Loop inner : loop.getChildren()) { + result.addAll(processLoop((HIRLoop) inner, modifiedInLoops)); + } + + for (Block b : loop.getBlocks()) { + if (b.getLoop() == loop) { + processBlock(b, result); + } + } + + modifiedInLoops.put(loopBegin, result); + return result; + } + @Override protected void run(StructuredGraph graph) { - Map> modifiedInLoops = Node.newIdentityMap(); - ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), CollectionsFactory.newSet()); + Map> modifiedInLoops = null; + if (graph.hasLoops()) { + modifiedInLoops = new HashMap<>(); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); + for (Loop l : cfg.getLoops()) { + HIRLoop loop = (HIRLoop) l; + processLoop(loop, modifiedInLoops); + } + } + HashSetNodeEventListener listener = new HashSetNodeEventListener(EnumSet.of(NODE_ADDED, ZERO_USAGES)); try (NodeEventScope nes = graph.trackNodeEvents(listener)) { ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, createFloatingReads, createMemoryMapNodes), graph.start(), new MemoryMapImpl(graph.start())); @@ -193,58 +241,6 @@ return true; } - public static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure> { - - private final Map> modifiedInLoops; - - public CollectMemoryCheckpointsClosure(Map> modifiedInLoops) { - this.modifiedInLoops = modifiedInLoops; - } - - @Override - protected Set processNode(FixedNode node, Set currentState) { - if (node instanceof MemoryCheckpoint.Single) { - currentState.add(((MemoryCheckpoint.Single) node).getLocationIdentity()); - } else if (node instanceof MemoryCheckpoint.Multi) { - for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) { - currentState.add(identity); - } - } - return currentState; - } - - @Override - protected Set merge(AbstractMergeNode merge, List> states) { - Set result = CollectionsFactory.newSet(); - for (Set other : states) { - result.addAll(other); - } - return result; - } - - @Override - protected Set afterSplit(AbstractBeginNode node, Set oldState) { - return CollectionsFactory.newSet(oldState); - } - - @Override - protected Map> processLoop(LoopBeginNode loop, Set initialState) { - LoopInfo> loopInfo = ReentrantNodeIterator.processLoop(this, loop, CollectionsFactory.newSet()); - Set modifiedLocations = CollectionsFactory.newSet(); - for (Set end : loopInfo.endStates.values()) { - modifiedLocations.addAll(end); - } - for (Set exit : loopInfo.exitStates.values()) { - exit.addAll(modifiedLocations); - exit.addAll(initialState); - } - assert checkNoImmutableLocations(modifiedLocations); - modifiedInLoops.put(loop, modifiedLocations); - return loopInfo.exitStates; - } - - } - public static class FloatingReadClosure extends NodeIteratorClosure { private final Map> modifiedInLoops; @@ -280,7 +276,7 @@ private static void processAccess(MemoryAccess access, MemoryMapImpl state) { LocationIdentity locationIdentity = access.getLocationIdentity(); - if (!locationIdentity.equals(LocationIdentity.ANY_LOCATION)) { + if (!locationIdentity.equals(LocationIdentity.any())) { MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity); access.setLastLocationAccess(lastLocationAccess); } @@ -297,7 +293,7 @@ } private static void processIdentity(LocationIdentity identity, MemoryCheckpoint checkpoint, MemoryMapImpl state) { - if (identity.equals(ANY_LOCATION)) { + if (identity.isAny()) { state.lastMemorySnapshot.clear(); } state.lastMemorySnapshot.put(identity, checkpoint); @@ -345,18 +341,15 @@ @Override protected Map processLoop(LoopBeginNode loop, MemoryMapImpl initialState) { Set modifiedLocations = modifiedInLoops.get(loop); - if (modifiedLocations.contains(ANY_LOCATION)) { + Map phis = CollectionsFactory.newMap(); + if (modifiedLocations.contains(LocationIdentity.any())) { // create phis for all locations if ANY is modified in the loop modifiedLocations = CollectionsFactory.newSet(modifiedLocations); modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet()); } - Map phis = CollectionsFactory.newMap(); - for (LocationIdentity location : modifiedLocations) { - MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location)); - phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location))); - phis.put(location, phi); + createMemoryPhi(loop, initialState, phis, location); } for (Map.Entry entry : phis.entrySet()) { initialState.lastMemorySnapshot.put(entry.getKey(), entry.getValue()); @@ -374,5 +367,11 @@ } return loopInfo.exitStates; } + + private static void createMemoryPhi(LoopBeginNode loop, MemoryMapImpl initialState, Map phis, LocationIdentity location) { + MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location)); + phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location))); + phis.put(location, phi); + } } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -289,7 +289,7 @@ final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode()); // Lower the instructions of this block. - List nodes = schedule.nodesFor(b); + List nodes = schedule.nodesFor(b); for (Node node : nodes) { if (node.isDeleted()) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -46,7 +46,7 @@ * a method and at each loop header. * * A schedule is created so that floating nodes can also be taken into account. The weight of a node - * is determined heuristically in the {@link ProfileCompiledMethodsPhase#getNodeWeight(ValueNode)} + * is determined heuristically in the {@link ProfileCompiledMethodsPhase#getNodeWeight(Node)} * method. * * Additionally, there's a second counter that's only increased for code sections without invokes. @@ -117,14 +117,14 @@ double count = 0; for (Block block : blocks) { double blockProbability = probabilities.applyAsDouble(block.getBeginNode()); - for (ValueNode node : schedule.getBlockToNodesMap().get(block)) { + for (Node node : schedule.getBlockToNodesMap().get(block)) { count += blockProbability * getNodeWeight(node); } } return count; } - private static double getNodeWeight(ValueNode node) { + private static double getNodeWeight(Node node) { if (node instanceof AbstractMergeNode) { return ((AbstractMergeNode) node).phiPredecessorCount(); } else if (node instanceof AbstractBeginNode || node instanceof AbstractEndNode || node instanceof MonitorIdNode || node instanceof ConstantNode || node instanceof ParameterNode || @@ -150,6 +150,8 @@ return node.successors().count(); } else if (node instanceof AbstractNewObjectNode) { return 10; + } else if (node instanceof VirtualState) { + return 0; } return 2; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Tue Mar 17 12:05:51 2015 +0100 @@ -211,10 +211,7 @@ if (callTarget.targetMethod() == null) { return "target method is null"; } - if (invoke.stateAfter() == null) { - // TODO (chaeubl): why should an invoke not have a state after? - return "the invoke has no after state"; - } + assert invoke.stateAfter() != null; if (!invoke.useForInlining()) { return "the invoke is marked to be not used for inlining"; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java Tue Mar 17 12:05:51 2015 +0100 @@ -40,7 +40,7 @@ private FixedWithNextNode lastFixed; private FixedWithNextNode reconnect; - private ListIterator iterator; + private ListIterator iterator; public void processNodes(Block block, SchedulePhase shedule) { lastFixed = block.getBeginNode(); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,26 +22,21 @@ */ package com.oracle.graal.phases.schedule; -import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.*; import java.util.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; -import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo; + +import edu.umd.cs.findbugs.annotations.*; public final class SchedulePhase extends Phase { @@ -75,234 +70,14 @@ LATEST_OUT_OF_LOOPS } - private class LocationSet { - private LocationIdentity firstLocation; - private List list; - - public LocationSet() { - list = null; - } - - public LocationSet(LocationSet other) { - this.firstLocation = other.firstLocation; - if (other.list != null && other.list.size() > 0) { - list = new ArrayList<>(other.list); - } - } - - private void initList() { - if (list == null) { - list = new ArrayList<>(4); - } - } - - public void add(LocationIdentity location) { - if (LocationIdentity.ANY_LOCATION.equals(location)) { - firstLocation = location; - list = null; - } else { - if (firstLocation == null) { - firstLocation = location; - } else if (LocationIdentity.ANY_LOCATION.equals(firstLocation)) { - return; - } else if (location.equals(firstLocation)) { - return; - } else { - initList(); - for (int i = 0; i < list.size(); ++i) { - LocationIdentity value = list.get(i); - if (location.equals(value)) { - return; - } - } - list.add(location); - } - } - } - - public void addAll(LocationSet other) { - if (other.firstLocation != null) { - add(other.firstLocation); - } - List otherList = other.list; - if (otherList != null) { - for (LocationIdentity l : otherList) { - add(l); - } - } - } - - public boolean contains(LocationIdentity locationIdentity) { - assert locationIdentity != null; - assert !locationIdentity.equals(LocationIdentity.ANY_LOCATION); - assert !locationIdentity.equals(LocationIdentity.FINAL_LOCATION); - if (LocationIdentity.ANY_LOCATION.equals(firstLocation)) { - return true; - } - if (locationIdentity.equals(firstLocation)) { - return true; - } - if (list != null) { - for (int i = 0; i < list.size(); ++i) { - LocationIdentity value = list.get(i); - if (locationIdentity.equals(value)) { - return true; - } - } - } - return false; - } - - public List getCopyAsList() { - ArrayList result = new ArrayList<>(); - if (firstLocation != null) { - result.add(firstLocation); - } - if (list != null) { - result.addAll(list); - } - return result; - } - } - - private class NewMemoryScheduleClosure extends BlockIteratorClosure { - private Node excludeNode; - private Block upperBoundBlock; - - public NewMemoryScheduleClosure(Node excludeNode, Block upperBoundBlock) { - this.excludeNode = excludeNode; - this.upperBoundBlock = upperBoundBlock; - } - - public NewMemoryScheduleClosure() { - this(null, null); - } - - @Override - protected LocationSet getInitialState() { - return cloneState(blockToKillSet.get(getCFG().getStartBlock())); - } - - @Override - protected LocationSet processBlock(Block block, LocationSet currentState) { - assert block != null; - currentState.addAll(computeKillSet(block, block == upperBoundBlock ? excludeNode : null)); - return currentState; - } - - @Override - protected LocationSet merge(Block merge, List states) { - assert merge.getBeginNode() instanceof AbstractMergeNode; - - LocationSet initKillSet = new LocationSet(); - for (LocationSet state : states) { - initKillSet.addAll(state); - } - - return initKillSet; - } - - @Override - protected LocationSet cloneState(LocationSet state) { - return new LocationSet(state); - } - - @Override - protected List processLoop(Loop loop, LocationSet state) { - LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, cloneState(state)); - - assert loop.getHeader().getBeginNode() instanceof LoopBeginNode; - LocationSet headerState = merge(loop.getHeader(), info.endStates); - - // second iteration, for propagating information to loop exits - info = ReentrantBlockIterator.processLoop(this, loop, cloneState(headerState)); - - return info.exitStates; - } - } - - /** - * gather all kill locations by iterating trough the nodes assigned to a block. - * - * assumptions: {@link MemoryCheckpoint MemoryCheckPoints} are {@link FixedNode FixedNodes}. - * - * @param block block to analyze - * @param excludeNode if null, compute normal set of kill locations. if != null, don't add kills - * until we reach excludeNode. - * @return all killed locations - */ - private LocationSet computeKillSet(Block block, Node excludeNode) { - // cache is only valid if we don't potentially exclude kills from the set - if (excludeNode == null) { - LocationSet cachedSet = blockToKillSet.get(block); - if (cachedSet != null) { - return cachedSet; - } - } - - // add locations to excludedLocations until we reach the excluded node - boolean foundExcludeNode = excludeNode == null; - - LocationSet set = new LocationSet(); - LocationSet excludedLocations = new LocationSet(); - if (block.getBeginNode() instanceof AbstractMergeNode) { - AbstractMergeNode mergeNode = (AbstractMergeNode) block.getBeginNode(); - for (MemoryPhiNode phi : mergeNode.usages().filter(MemoryPhiNode.class)) { - if (foundExcludeNode) { - set.add(phi.getLocationIdentity()); - } else { - excludedLocations.add(phi.getLocationIdentity()); - foundExcludeNode = phi == excludeNode; - } - } - } - - AbstractBeginNode startNode = cfg.getStartBlock().getBeginNode(); - assert startNode instanceof StartNode; - - LocationSet accm = foundExcludeNode ? set : excludedLocations; - for (Node node : block.getNodes()) { - if (!foundExcludeNode && node == excludeNode) { - foundExcludeNode = true; - } - if (node != startNode) { - if (node instanceof MemoryCheckpoint.Single) { - LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); - accm.add(identity); - } else if (node instanceof MemoryCheckpoint.Multi) { - for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) { - accm.add(identity); - } - } - assert MemoryCheckpoint.TypeAssertion.correctType(node); - } - - if (foundExcludeNode) { - accm = set; - } - } - - // merge it for the cache entry - excludedLocations.addAll(set); - blockToKillSet.put(block, excludedLocations); - - return set; - } - - private LocationSet computeKillSet(Block block) { - return computeKillSet(block, null); - } - private ControlFlowGraph cfg; - private NodeMap earliestCache; /** * Map from blocks to the nodes in each block. */ - private BlockMap> blockToNodesMap; + private BlockMap> blockToNodesMap; private BlockMap blockToKillSet; private final SchedulingStrategy selectedStrategy; - private boolean scheduleConstants; private NodeMap nodeToBlockMap; public SchedulePhase() { @@ -313,41 +88,373 @@ this.selectedStrategy = strategy; } - public void setScheduleConstants(boolean value) { - scheduleConstants = value; - } - @Override protected void run(StructuredGraph graph) { // assert GraphOrder.assertNonCyclicGraph(graph); cfg = ControlFlowGraph.compute(graph, true, true, true, false); - earliestCache = graph.createNodeMap(); - blockToNodesMap = new BlockMap<>(cfg); + + if (selectedStrategy == SchedulingStrategy.EARLIEST) { + this.nodeToBlockMap = graph.createNodeMap(); + this.blockToNodesMap = new BlockMap<>(cfg); + NodeBitMap visited = graph.createNodeBitMap(); + scheduleEarliestIterative(cfg, blockToNodesMap, nodeToBlockMap, visited, graph); + return; + } else { + boolean isOutOfLoops = selectedStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS; + if (selectedStrategy == SchedulingStrategy.LATEST || isOutOfLoops) { + NodeMap currentNodeMap = graph.createNodeMap(); + BlockMap> earliestBlockToNodesMap = new BlockMap<>(cfg); + NodeBitMap visited = graph.createNodeBitMap(); + scheduleEarliestIterative(cfg, earliestBlockToNodesMap, currentNodeMap, visited, graph); + BlockMap> latestBlockToNodesMap = new BlockMap<>(cfg); + + for (Block b : cfg.getBlocks()) { + latestBlockToNodesMap.put(b, new ArrayList()); + } + + BlockMap> watchListMap = calcLatestBlocks(isOutOfLoops, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap); + sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited); + + this.blockToNodesMap = latestBlockToNodesMap; + this.nodeToBlockMap = currentNodeMap; + + assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap); + cfg.setNodeToBlock(currentNodeMap); + } + } + } + + @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "false positive found by findbugs") + private BlockMap> calcLatestBlocks(boolean isOutOfLoops, NodeMap currentNodeMap, BlockMap> earliestBlockToNodesMap, NodeBitMap visited, + BlockMap> latestBlockToNodesMap) { + BlockMap> watchListMap = null; + for (Block b : cfg.postOrder()) { + List blockToNodes = earliestBlockToNodesMap.get(b); + LocationSet killed = null; + int previousIndex = blockToNodes.size(); + for (int i = blockToNodes.size() - 1; i >= 0; --i) { + Node currentNode = blockToNodes.get(i); + assert currentNodeMap.get(currentNode) == b; + assert !(currentNode instanceof PhiNode) && !(currentNode instanceof ProxyNode); + assert visited.isMarked(currentNode); + if (currentNode instanceof FixedNode) { + // For these nodes, the earliest is at the same time the latest block. + } else { + Block currentBlock = b; + assert currentBlock != null; + Block latestBlock = calcLatestBlock(b, isOutOfLoops, currentNode, currentNodeMap); + assert AbstractControlFlowGraph.dominates(currentBlock, latestBlock) || currentNode instanceof VirtualState : currentNode + " " + currentBlock + " " + latestBlock; + if (latestBlock != currentBlock) { + if (currentNode instanceof FloatingReadNode) { - if (selectedStrategy != SchedulingStrategy.EARLIEST && graph.isAfterFloatingReadPhase()) { - blockToKillSet = new BlockMap<>(cfg); + FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode; + LocationIdentity location = floatingReadNode.getLocationIdentity(); + if (location.isMutable()) { + if (currentBlock.canKill(location)) { + if (killed == null) { + killed = new LocationSet(); + } + fillKillSet(killed, blockToNodes.subList(i + 1, previousIndex)); + previousIndex = i; + if (killed.contains(location)) { + latestBlock = currentBlock; + } + } + + if (latestBlock != currentBlock) { + // We are not constraint within currentBlock. Check if + // we are contraint while walking down the dominator + // line. + Block newLatestBlock = adjustLatestForRead(currentBlock, latestBlock, location); + assert dominates(newLatestBlock, latestBlock); + assert dominates(currentBlock, newLatestBlock); + latestBlock = newLatestBlock; + + if (newLatestBlock != currentBlock && latestBlock.canKill(location)) { + if (watchListMap == null) { + watchListMap = new BlockMap<>(cfg); + } + if (watchListMap.get(latestBlock) == null) { + watchListMap.put(latestBlock, new ArrayList<>()); + } + watchListMap.get(latestBlock).add(floatingReadNode); + } + } + } + } + currentNodeMap.set(currentNode, latestBlock); + currentBlock = latestBlock; + } + latestBlockToNodesMap.get(currentBlock).add(currentNode); + } + } + } + return watchListMap; + } + + private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap> blockToNodesMap, NodeMap nodeMap) { + for (Block b : cfg.getBlocks()) { + List nodes = blockToNodesMap.get(b); + for (Node n : nodes) { + assert n.isAlive(); + assert nodeMap.get(n) == b; + } + } + return true; + } + + private static Block adjustLatestForRead(Block earliestBlock, Block latestBlock, LocationIdentity location) { + assert strictlyDominates(earliestBlock, latestBlock); + Block current = latestBlock.getDominator(); + + // Collect dominator chain that needs checking. + List dominatorChain = new ArrayList<>(); + dominatorChain.add(latestBlock); + while (current != earliestBlock) { + // Current is an intermediate dominator between earliestBlock and latestBlock. + assert strictlyDominates(earliestBlock, current) && strictlyDominates(current, latestBlock); + if (current.canKill(location)) { + dominatorChain.clear(); + } + dominatorChain.add(current); + current = current.getDominator(); } - if (selectedStrategy == SchedulingStrategy.EARLIEST) { - scheduleEarliestIterative(blockToNodesMap, graph); + // The first element of dominatorChain now contains the latest possible block. + assert dominatorChain.size() >= 1; + assert dominatorChain.get(dominatorChain.size() - 1).getDominator() == earliestBlock; + + Block lastBlock = earliestBlock; + for (int i = dominatorChain.size() - 1; i >= 0; --i) { + Block currentBlock = dominatorChain.get(i); + if (lastBlock.getLoop() != currentBlock.getLoop()) { + // We are crossing a loop boundary. Both loops must not kill the location for the + // crossing to be safe. + if (lastBlock.getLoop() != null && ((HIRLoop) lastBlock.getLoop()).canKill(location)) { + break; + } + if (currentBlock.getLoop() != null && ((HIRLoop) currentBlock.getLoop()).canKill(location)) { + break; + } + } + + if (currentBlock.canKillBetweenThisAndDominator(location)) { + break; + } + lastBlock = currentBlock; + } + + return lastBlock; + } + + private static void fillKillSet(LocationSet killed, List subList) { + if (!killed.isAny()) { + for (Node n : subList) { + // Check if this node kills a node in the watch list. + if (n instanceof MemoryCheckpoint.Single) { + LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity(); + killed.add(identity); + if (killed.isAny()) { + return; + } + } else if (n instanceof MemoryCheckpoint.Multi) { + for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) { + killed.add(identity); + if (killed.isAny()) { + return; + } + } + } + } + } + } + + private static void sortNodesLatestWithinBlock(ControlFlowGraph cfg, BlockMap> earliestBlockToNodesMap, BlockMap> latestBlockToNodesMap, NodeMap currentNodeMap, + BlockMap> watchListMap, NodeBitMap visited) { + for (Block b : cfg.getBlocks()) { + sortNodesLatestWithinBlock(b, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited); + } + } + + private static void sortNodesLatestWithinBlock(Block b, BlockMap> earliestBlockToNodesMap, BlockMap> latestBlockToNodesMap, NodeMap nodeMap, + BlockMap> watchListMap, NodeBitMap unprocessed) { + List earliestSorting = earliestBlockToNodesMap.get(b); + ArrayList result = new ArrayList<>(earliestSorting.size()); + ArrayList watchList = null; + if (watchListMap != null) { + watchList = watchListMap.get(b); + assert watchList == null || !b.getKillLocations().isEmpty(); + } + AbstractBeginNode beginNode = b.getBeginNode(); + if (beginNode instanceof LoopExitNode) { + LoopExitNode loopExitNode = (LoopExitNode) beginNode; + for (ProxyNode proxy : loopExitNode.proxies()) { + unprocessed.clear(proxy); + ValueNode value = proxy.value(); + if (nodeMap.get(value) == b) { + sortIntoList(value, b, result, nodeMap, unprocessed, null); + } + } + } + FixedNode endNode = b.getEndNode(); + for (Node n : earliestSorting) { + if (n != endNode) { + if (n instanceof FixedNode) { + assert nodeMap.get(n) == b; + checkWatchList(b, nodeMap, unprocessed, result, watchList, n); + sortIntoList(n, b, result, nodeMap, unprocessed, null); + } else if (nodeMap.get(n) == b && n instanceof FloatingReadNode) { + FloatingReadNode floatingReadNode = (FloatingReadNode) n; + LocationIdentity location = floatingReadNode.getLocationIdentity(); + if (b.canKill(location)) { + // This read can be killed in this block, add to watch list. + if (watchList == null) { + watchList = new ArrayList<>(); + } + watchList.add(floatingReadNode); + } + } + } + } + + for (Node n : latestBlockToNodesMap.get(b)) { + assert nodeMap.get(n) == b; + assert !(n instanceof FixedNode); + if (unprocessed.isMarked(n)) { + sortIntoList(n, b, result, nodeMap, unprocessed, endNode); + } + } + + if (unprocessed.isMarked(endNode)) { + sortIntoList(endNode, b, result, nodeMap, unprocessed, null); + } + + latestBlockToNodesMap.put(b, result); + } + + private static void checkWatchList(Block b, NodeMap nodeMap, NodeBitMap unprocessed, ArrayList result, ArrayList watchList, Node n) { + if (watchList != null && !watchList.isEmpty()) { + // Check if this node kills a node in the watch list. + if (n instanceof MemoryCheckpoint.Single) { + LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity(); + checkWatchList(watchList, identity, b, result, nodeMap, unprocessed); + } else if (n instanceof MemoryCheckpoint.Multi) { + for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) { + checkWatchList(watchList, identity, b, result, nodeMap, unprocessed); + } + } + } + } + + private static void checkWatchList(ArrayList watchList, LocationIdentity identity, Block b, ArrayList result, NodeMap nodeMap, NodeBitMap unprocessed) { + assert identity.isMutable(); + if (identity.isAny()) { + for (FloatingReadNode r : watchList) { + if (unprocessed.isMarked(r)) { + sortIntoList(r, b, result, nodeMap, unprocessed, null); + } + } + watchList.clear(); + } else { + int index = 0; + while (index < watchList.size()) { + FloatingReadNode r = watchList.get(index); + LocationIdentity locationIdentity = r.getLocationIdentity(); + assert locationIdentity.isMutable(); + if (unprocessed.isMarked(r)) { + if (identity.overlaps(locationIdentity)) { + sortIntoList(r, b, result, nodeMap, unprocessed, null); + } else { + ++index; + continue; + } + } + int lastIndex = watchList.size() - 1; + watchList.set(index, watchList.get(lastIndex)); + watchList.remove(lastIndex); + } + } + } + + private static void sortIntoList(Node n, Block b, ArrayList result, NodeMap nodeMap, NodeBitMap unprocessed, Node excludeNode) { + assert unprocessed.isMarked(n) : n; + unprocessed.clear(n); + + assert nodeMap.get(n) == b; + + if (n instanceof PhiNode) { return; } - assignBlockToNodes(graph, selectedStrategy); - printSchedule("after assign nodes to blocks"); + for (Node input : n.inputs()) { + if (nodeMap.get(input) == b && unprocessed.isMarked(input) && input != excludeNode) { + sortIntoList(input, b, result, nodeMap, unprocessed, excludeNode); + } + } - sortNodesWithinBlocks(graph, selectedStrategy); - printSchedule("after sorting nodes within blocks"); + if (n instanceof ProxyNode) { + // Skip proxy nodes. + } else { + result.add(n); + } + } - private void scheduleEarliestIterative(BlockMap> blockToNodes, StructuredGraph graph) { - NodeMap nodeToBlock = graph.createNodeMap(); - NodeBitMap visited = graph.createNodeBitMap(); + private static Block calcLatestBlock(Block earliestBlock, boolean scheduleOutOfLoops, Node currentNode, NodeMap currentNodeMap) { + Block block = null; + assert currentNode.hasUsages(); + for (Node usage : currentNode.usages()) { + block = calcBlockForUsage(currentNode, usage, block, currentNodeMap); + if (scheduleOutOfLoops) { + while (block.getLoopDepth() > earliestBlock.getLoopDepth()) { + block = block.getDominator(); + } + } + if (block == earliestBlock) { + // No need to search further. The earliest block *must* be a valid schedule block. + break; + } + } + assert block != null : currentNode; + return block; + } + + private static Block calcBlockForUsage(Node node, Node usage, Block startCurrentBlock, NodeMap currentNodeMap) { + assert !(node instanceof PhiNode); + Block currentBlock = startCurrentBlock; + if (usage instanceof PhiNode) { + // An input to a PhiNode is used at the end of the predecessor block that corresponds to + // the PhiNode input. One PhiNode can use an input multiple times. + PhiNode phi = (PhiNode) usage; + AbstractMergeNode merge = phi.merge(); + Block mergeBlock = currentNodeMap.get(merge); + for (int i = 0; i < phi.valueCount(); ++i) { + if (phi.valueAt(i) == node) { + currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, mergeBlock.getPredecessors().get(i)); + } + } + } else if (usage instanceof AbstractBeginNode) { + AbstractBeginNode abstractBeginNode = (AbstractBeginNode) usage; + if (abstractBeginNode instanceof StartNode) { + currentBlock = currentNodeMap.get(abstractBeginNode); + } else { + currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(abstractBeginNode).getDominator()); + } + } else { + // All other types of usages: Put the input into the same block as the usage. + currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(usage)); + } + return currentBlock; + } + + private static void scheduleEarliestIterative(ControlFlowGraph cfg, BlockMap> blockToNodes, NodeMap nodeToBlock, NodeBitMap visited, StructuredGraph graph) { + + BitSet floatingReads = new BitSet(cfg.getBlocks().size()); // Add begin nodes as the first entry and set the block for phi nodes. for (Block b : cfg.getBlocks()) { AbstractBeginNode beginNode = b.getBeginNode(); - ArrayList nodes = new ArrayList<>(); + ArrayList nodes = new ArrayList<>(); nodeToBlock.set(beginNode, b); nodes.add(beginNode); blockToNodes.put(b, nodes); @@ -365,7 +472,7 @@ } } - Stack stack = new Stack<>(); + NodeStack stack = new NodeStack(); // Start analysis with control flow ends. for (Block b : cfg.postOrder()) { @@ -374,10 +481,9 @@ nodeToBlock.set(endNode, b); } - processStack(blockToNodes, nodeToBlock, visited, stack); + processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack); // Visit back input edges of loop phis. - boolean changed; boolean unmarkedPhi; do { @@ -391,7 +497,7 @@ if (node != null && !visited.isMarked(node)) { changed = true; stack.push(node); - processStack(blockToNodes, nodeToBlock, visited, stack); + processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack); } } } else { @@ -424,16 +530,83 @@ } } - this.blockToNodesMap = blockToNodes; - this.nodeToBlockMap = nodeToBlock; + if (!floatingReads.isEmpty()) { + for (Block b : cfg.getBlocks()) { + if (floatingReads.get(b.getId())) { + resortEarliestWithinBlock(b, blockToNodes, nodeToBlock, visited); + } + } + } } - private static void addNode(BlockMap> blockToNodes, Block b, ValueNode endNode) { + private static void resortEarliestWithinBlock(Block b, BlockMap> blockToNodes, NodeMap nodeToBlock, NodeBitMap unprocessed) { + ArrayList watchList = new ArrayList<>(); + List oldList = blockToNodes.get(b); + AbstractBeginNode beginNode = b.getBeginNode(); + for (Node n : oldList) { + if (n instanceof FloatingReadNode) { + FloatingReadNode floatingReadNode = (FloatingReadNode) n; + LocationIdentity locationIdentity = floatingReadNode.getLocationIdentity(); + MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess(); + if (locationIdentity.isMutable() && lastLocationAccess != null) { + ValueNode lastAccessLocation = lastLocationAccess.asNode(); + if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode) { + // This node's last access location is within this block. Add to watch list + // when processing the last access location. + } else { + watchList.add(floatingReadNode); + } + } + } + } + + ArrayList newList = new ArrayList<>(oldList.size()); + assert oldList.get(0) == beginNode; + unprocessed.clear(beginNode); + newList.add(beginNode); + for (int i = 1; i < oldList.size(); ++i) { + Node n = oldList.get(i); + if (unprocessed.isMarked(n)) { + if (n instanceof MemoryCheckpoint) { + assert n instanceof FixedNode; + if (watchList.size() > 0) { + // Check whether we need to commit reads from the watch list. + checkWatchList(b, nodeToBlock, unprocessed, newList, watchList, n); + } + + // Add potential dependent reads to the watch list. + for (Node usage : n.usages()) { + if (usage instanceof FloatingReadNode) { + FloatingReadNode floatingReadNode = (FloatingReadNode) usage; + if (nodeToBlock.get(floatingReadNode) == b && floatingReadNode.getLastLocationAccess() == n) { + watchList.add(floatingReadNode); + } + } + } + } + assert unprocessed.isMarked(n); + unprocessed.clear(n); + newList.add(n); + } else { + // This node was pulled up. + assert !(n instanceof FixedNode) : n; + } + } + + for (Node n : newList) { + unprocessed.mark(n); + } + + assert newList.size() == oldList.size(); + blockToNodes.put(b, newList); + } + + private static void addNode(BlockMap> blockToNodes, Block b, Node endNode) { assert !blockToNodes.get(b).contains(endNode) : endNode; blockToNodes.get(b).add(endNode); } - private void processStack(BlockMap> blockToNodes, NodeMap nodeToBlock, NodeBitMap visited, Stack stack) { + private static void processStack(ControlFlowGraph cfg, BlockMap> blockToNodes, NodeMap nodeToBlock, NodeBitMap visited, BitSet floatingReads, NodeStack stack) { Block startBlock = cfg.getStartBlock(); while (!stack.isEmpty()) { Node current = stack.peek(); @@ -455,12 +628,16 @@ } } } else { - for (Node input : current.inputs()) { - if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) { - // Ignore the cycle. - } else { - stack.push(input); + if (current instanceof FrameState) { + for (Node input : current.inputs()) { + if (input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) { + // Ignore the cycle. + } else { + stack.push(input); + } } + } else { + current.pushInputs(stack); } } } else { @@ -468,24 +645,21 @@ stack.pop(); if (nodeToBlock.get(current) == null) { - Node predecessor = current.predecessor(); - Block curBlock; - if (predecessor != null) { - // Predecessor determines block. - curBlock = nodeToBlock.get(predecessor); - } else { + Block curBlock = cfg.blockFor(current); + if (curBlock == null) { + assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg."; Block earliest = startBlock; for (Node input : current.inputs()) { - if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) { - // ignore + Block inputEarliest; + if (input instanceof ControlSplitNode) { + inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor()); } else { - Block inputEarliest; - if (input instanceof ControlSplitNode) { - inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor()); - } else { - inputEarliest = nodeToBlock.get(input); - } - assert inputEarliest != null : current + " / " + input; + inputEarliest = nodeToBlock.get(input); + } + if (inputEarliest == null) { + assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current; + } else { + assert inputEarliest != null; if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) { earliest = inputEarliest; } @@ -494,32 +668,20 @@ curBlock = earliest; } assert curBlock != null; - if (current instanceof ValueNode) { - addNode(blockToNodes, curBlock, (ValueNode) current); + addNode(blockToNodes, curBlock, current); + nodeToBlock.set(current, curBlock); + if (current instanceof FloatingReadNode) { + FloatingReadNode floatingReadNode = (FloatingReadNode) current; + if (curBlock.canKill(floatingReadNode.getLocationIdentity())) { + floatingReads.set(curBlock.getId()); + } } - nodeToBlock.set(current, curBlock); } } } } - private Block blockForMemoryNode(MemoryNode memory) { - MemoryNode current = memory; - while (current instanceof MemoryProxy) { - current = ((MemoryProxy) current).getOriginalMemoryNode(); - } - Block b = cfg.getNodeToBlock().get(current.asNode()); - assert b != null : "all lastAccess locations should have a block assignment from CFG"; - return b; - } - - private void printSchedule(String desc) { - if (Debug.isLogEnabled()) { - printScheduleHelper(desc); - } - } - - private void printScheduleHelper(String desc) { + public String printScheduleHelper(String desc) { Formatter buf = new Formatter(); buf.format("=== %s / %s / %s ===%n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, desc); for (Block b : getCFG().getBlocks()) { @@ -548,7 +710,7 @@ } } buf.format("%n"); - Debug.log("%s", buf); + return buf.toString(); } private static void printNode(Node n) { @@ -579,7 +741,7 @@ /** * Gets the map from each block to the nodes in the block. */ - public BlockMap> getBlockToNodesMap() { + public BlockMap> getBlockToNodesMap() { return blockToNodesMap; } @@ -590,660 +752,7 @@ /** * Gets the nodes in a given block. */ - public List nodesFor(Block block) { + public List nodesFor(Block block) { return blockToNodesMap.get(block); } - - private void assignBlockToNodes(StructuredGraph graph, SchedulingStrategy strategy) { - for (Block block : cfg.getBlocks()) { - List nodes = new ArrayList<>(); - if (blockToNodesMap.get(block) != null) { - throw new SchedulingError(); - } - blockToNodesMap.put(block, nodes); - for (FixedNode node : block.getNodes()) { - nodes.add(node); - } - } - - for (Node n : graph.getNodes()) { - if (n instanceof ValueNode) { - assignBlockToNode((ValueNode) n, strategy); - } - } - } - - /** - * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are - * already assigned to a block. - */ - private void assignBlockToNode(ValueNode node, SchedulingStrategy strategy) { - assert !node.isDeleted(); - - if (cfg.getNodeToBlock().containsKey(node)) { - return; - } - if (!scheduleConstants && node instanceof ConstantNode) { - return; - } - if (node instanceof VirtualObjectNode) { - return; - } - // PhiNodes, ProxyNodes and FixedNodes should already have been placed in blocks by - // ControlFlowGraph.identifyBlocks - if (node instanceof PhiNode || node instanceof ProxyNode || node instanceof FixedNode) { - throw new SchedulingError("%s should already have been placed in a block", node); - } - - Block earliestBlock = earliestBlock(node); - Block block = null; - Block latest = null; - switch (strategy) { - case EARLIEST: - block = earliestBlock; - break; - case LATEST: - case LATEST_OUT_OF_LOOPS: - boolean scheduleRead = node instanceof FloatingReadNode && !((FloatingReadNode) node).location().getLocationIdentity().isImmutable(); - if (scheduleRead) { - FloatingReadNode read = (FloatingReadNode) node; - block = optimalBlock(read, strategy); - Debug.log("schedule for %s: %s", read, block); - assert dominates(earliestBlock, block) : String.format("%s (%s) cannot be scheduled before earliest schedule (%s). location: %s", read, block, earliestBlock, - read.getLocationIdentity()); - } else { - block = latestBlock(node, strategy, earliestBlock); - } - if (block == null) { - // handle nodes without usages - block = earliestBlock; - } else if (strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS && !(node instanceof VirtualObjectNode)) { - // schedule at the latest position possible in the outermost loop possible - latest = block; - block = scheduleOutOfLoops(node, block, earliestBlock); - } - - assert assertReadSchedule(node, earliestBlock, block, latest, scheduleRead); - break; - default: - throw new GraalInternalError("unknown scheduling strategy"); - } - if (!dominates(earliestBlock, block)) { - throw new SchedulingError("%s: Graph cannot be scheduled : inconsistent for %s, %d usages, (%s needs to dominate %s)", node.graph(), node, node.getUsageCount(), earliestBlock, block); - } - cfg.getNodeToBlock().set(node, block); - blockToNodesMap.get(block).add(node); - } - - private boolean assertReadSchedule(ValueNode node, Block earliestBlock, Block block, Block latest, boolean scheduleRead) { - if (scheduleRead) { - FloatingReadNode read = (FloatingReadNode) node; - MemoryNode lastLocationAccess = read.getLastLocationAccess(); - Block upperBound = blockForMemoryNode(lastLocationAccess); - assert dominates(upperBound, block) : String.format("out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)", - read, read.getLocationIdentity(), block, upperBound, earliestBlock, latest); - } - return true; - } - - /** - * this method tries to find the "optimal" schedule for a read, by pushing it down towards its - * latest schedule starting by the earliest schedule. By doing this, it takes care of memory - * dependencies using kill sets. - * - * In terms of domination relation, it looks like this: - * - *

-     *    U      upperbound block, defined by last access location of the floating read
-     *    ∧
-     *    E      earliest block
-     *    ∧
-     *    O      optimal block, first block that contains a kill of the read's location
-     *    ∧
-     *    L      latest block
-     * 
- * - * i.e. upperbound `dom` earliest `dom` optimal `dom` latest. - * - */ - private Block optimalBlock(FloatingReadNode n, SchedulingStrategy strategy) { - LocationIdentity locid = n.location().getLocationIdentity(); - assert !locid.isImmutable(); - - Block upperBoundBlock = blockForMemoryNode(n.getLastLocationAccess()); - Block earliestBlock = earliestBlock(n); - assert dominates(upperBoundBlock, earliestBlock) : "upper bound (" + upperBoundBlock + ") should dominate earliest (" + earliestBlock + ")"; - - Block latestBlock = latestBlock(n, strategy, earliestBlock); - assert latestBlock != null && dominates(earliestBlock, latestBlock) : "earliest (" + earliestBlock + ") should dominate latest block (" + latestBlock + ")"; - - Debug.log("processing %s (accessing %s): latest %s, earliest %s, upper bound %s (%s)", n, locid, latestBlock, earliestBlock, upperBoundBlock, n.getLastLocationAccess()); - if (earliestBlock == latestBlock) { - // read is fixed to this block, nothing to schedule - return latestBlock; - } - - Deque path = computePathInDominatorTree(earliestBlock, latestBlock); - Debug.log("|path| is %d: %s", path.size(), path); - - // follow path, start at earliest schedule - while (path.size() > 0) { - Block currentBlock = path.pop(); - Block dominatedBlock = path.size() == 0 ? null : path.peek(); - if (dominatedBlock != null && !currentBlock.getSuccessors().contains(dominatedBlock)) { - // the dominated block is not a successor -> we have a split - assert dominatedBlock.getBeginNode() instanceof AbstractMergeNode; - - NewMemoryScheduleClosure closure = null; - if (currentBlock == upperBoundBlock) { - assert earliestBlock == upperBoundBlock; - // don't treat lastLocationAccess node as a kill for this read. - closure = new NewMemoryScheduleClosure(ValueNodeUtil.asNode(n.getLastLocationAccess()), upperBoundBlock); - } else { - closure = new NewMemoryScheduleClosure(); - } - Map states; - states = ReentrantBlockIterator.apply(closure, currentBlock, new LocationSet(), block -> block == dominatedBlock); - - LocationSet mergeState = states.get(dominatedBlock.getBeginNode()); - if (mergeState.contains(locid)) { - // location got killed somewhere in the branches, - // thus we've to move the read above it - return currentBlock; - } - } else { - if (currentBlock == upperBoundBlock) { - assert earliestBlock == upperBoundBlock; - LocationSet ks = computeKillSet(upperBoundBlock, ValueNodeUtil.asNode(n.getLastLocationAccess())); - if (ks.contains(locid)) { - return upperBoundBlock; - } - } else if (dominatedBlock == null || computeKillSet(currentBlock).contains(locid)) { - return currentBlock; - } - } - } - throw new SchedulingError("should have found a block for " + n); - } - - /** - * compute path in dominator tree from earliest schedule to latest schedule. - * - * @return the order of the stack is such as the first element is the earliest schedule. - */ - private static Deque computePathInDominatorTree(Block earliestBlock, Block latestBlock) { - Deque path = new LinkedList<>(); - Block currentBlock = latestBlock; - while (currentBlock != null && dominates(earliestBlock, currentBlock)) { - path.push(currentBlock); - currentBlock = currentBlock.getDominator(); - } - assert path.peek() == earliestBlock; - return path; - } - - /** - * Calculates the last block that the given node could be scheduled in, i.e., the common - * dominator of all usages. To do so all usages are also assigned to blocks. - * - * @param strategy - * @param earliestBlock - */ - private Block latestBlock(ValueNode node, SchedulingStrategy strategy, Block earliestBlock) { - Block block = null; - for (Node usage : node.usages()) { - block = blocksForUsage(node, usage, block, earliestBlock, strategy); - if (block == earliestBlock) { - break; - } - } - - assert assertLatestBlockResult(node, block); - return block; - } - - private boolean assertLatestBlockResult(ValueNode node, Block block) throws SchedulingError { - if (block != null && !dominates(earliestBlock(node), block)) { - throw new SchedulingError("failed to find correct latest schedule for %s. cdbc: %s, earliest: %s", node, block, earliestBlock(node)); - } - return true; - } - - /** - * Determines the earliest block in which the given node can be scheduled. - */ - private Block earliestBlock(Node node) { - Block earliest = cfg.getNodeToBlock().get(node); - if (earliest != null) { - return earliest; - } - earliest = earliestCache.get(node); - if (earliest != null) { - return earliest; - } - return earliestBlockHelper(node, earliest); - } - - private Block earliestBlockHelper(Node node, Block earliestStart) throws SchedulingError { - /* - * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This - * implies that the inputs' blocks have a total ordering via their dominance relation. So in - * order to find the earliest block placement for this node we need to find the input block - * that is dominated by all other input blocks. - */ - Block earliest = earliestStart; - - if (node.predecessor() != null) { - throw new SchedulingError(); - } - for (Node input : node.inputs()) { - if (input != null) { - assert input instanceof ValueNode; - Block inputEarliest; - if (input instanceof InvokeWithExceptionNode) { - inputEarliest = cfg.getNodeToBlock().get(((InvokeWithExceptionNode) input).next()); - } else { - inputEarliest = earliestBlock(input); - } - if (earliest == null || earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) { - earliest = inputEarliest; - } - } - } - if (earliest == null) { - earliest = cfg.getStartBlock(); - } - earliestCache.set(node, earliest); - return earliest; - } - - /** - * Schedules a node out of loop based on its earliest schedule. Note that this movement is only - * valid if it's done for every other node in the schedule, otherwise this movement is - * not valid. - * - * @param n Node to schedule - * @param latestBlock latest possible schedule for {@code n} - * @param earliest earliest possible schedule for {@code n} - * @return block schedule for {@code n} which is not inside a loop (if possible) - */ - private static Block scheduleOutOfLoops(Node n, Block latestBlock, Block earliest) { - if (latestBlock == null) { - throw new SchedulingError("no latest : %s", n); - } - Block cur = latestBlock; - Block result = latestBlock; - Loop earliestLoop = earliest.getLoop(); - while (true) { - Loop curLoop = cur.getLoop(); - if (curLoop == earliestLoop) { - return result; - } else { - Block dom = cur.getDominator(); - if (dom.getLoopDepth() < result.getLoopDepth()) { - result = dom; - } - cur = dom; - } - } - } - - /** - * Passes all blocks that a specific usage of a node is in to a given closure. This is more - * complex than just taking the usage's block because of of PhiNodes and FrameStates. - * - * @param node the node that needs to be scheduled - * @param usage the usage whose blocks need to be considered - * @param earliestBlock - */ - private Block blocksForUsage(ValueNode node, Node usage, Block startCurrentBlock, Block earliestBlock, SchedulingStrategy strategy) { - assert !(node instanceof PhiNode); - Block currentBlock = startCurrentBlock; - if (usage instanceof PhiNode) { - // An input to a PhiNode is used at the end of the predecessor block that corresponds to - // the PhiNode input. - // One PhiNode can use an input multiple times, the closure will be called for each - // usage. - PhiNode phi = (PhiNode) usage; - AbstractMergeNode merge = phi.merge(); - Block mergeBlock = cfg.getNodeToBlock().get(merge); - for (int i = 0; i < phi.valueCount(); ++i) { - if (phi.valueAt(i) == node) { - currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, mergeBlock.getPredecessors().get(i)); - if (currentBlock == earliestBlock) { - break; - } - } - } - } else if (usage instanceof VirtualState) { - // The following logic does not work if node is a PhiNode, but this method is never - // called for PhiNodes. - for (Node unscheduledUsage : usage.usages()) { - if (unscheduledUsage instanceof VirtualState) { - // If a FrameState is an outer FrameState this method behaves as if the inner - // FrameState was the actual usage, by recursing. - currentBlock = blocksForUsage(node, unscheduledUsage, currentBlock, earliestBlock, strategy); - } else if (unscheduledUsage instanceof AbstractBeginNode) { - // Only FrameStates can be connected to BeginNodes. - if (!(usage instanceof FrameState)) { - throw new SchedulingError(usage.toString()); - } - if (unscheduledUsage instanceof StartNode) { - currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(unscheduledUsage)); - } else { - // If a FrameState belongs to a BeginNode then it's inputs will be placed at - // the common dominator of all EndNodes. - for (Node pred : unscheduledUsage.cfgPredecessors()) { - currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(pred)); - } - } - } else { - // For the time being, FrameStates can only be connected to NodeWithState. - if (!(usage instanceof FrameState)) { - throw new SchedulingError(usage.toString()); - } - if (!(unscheduledUsage instanceof NodeWithState)) { - throw new SchedulingError(unscheduledUsage.toString()); - } - // Otherwise: Put the input into the same block as the usage. - assignBlockToNode((ValueNode) unscheduledUsage, strategy); - currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(unscheduledUsage)); - } - if (currentBlock == earliestBlock) { - break; - } - } - } else { - // All other types of usages: Put the input into the same block as the usage. - assignBlockToNode((ValueNode) usage, strategy); - currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(usage)); - } - return currentBlock; - } - - private void sortNodesWithinBlocks(StructuredGraph graph, SchedulingStrategy strategy) { - NodeBitMap visited = graph.createNodeBitMap(); - NodeBitMap beforeLastLocation = graph.createNodeBitMap(); - for (Block b : cfg.getBlocks()) { - sortNodesWithinBlock(b, visited, beforeLastLocation, strategy); - assert noDuplicatedNodesInBlock(b) : "duplicated nodes in " + b; - } - } - - private boolean noDuplicatedNodesInBlock(Block b) { - List list = blockToNodesMap.get(b); - Set hashset = Node.newSet(list); - return list.size() == hashset.size(); - } - - private void sortNodesWithinBlock(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation, SchedulingStrategy strategy) { - if (visited.isMarked(b.getBeginNode()) || cfg.blockFor(b.getBeginNode()) != b) { - throw new SchedulingError(); - } - if (visited.isMarked(b.getEndNode()) || cfg.blockFor(b.getEndNode()) != b) { - throw new SchedulingError(); - } - - List sortedInstructions; - assert strategy == SchedulingStrategy.LATEST || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS; - sortedInstructions = sortNodesWithinBlockLatest(b, visited, beforeLastLocation); - assert filterSchedulableNodes(blockToNodesMap.get(b)).size() == removeProxies(sortedInstructions).size() : "sorted block does not contain the same amount of nodes: " + - filterSchedulableNodes(blockToNodesMap.get(b)) + " vs. " + removeProxies(sortedInstructions); - assert sameOrderForFixedNodes(blockToNodesMap.get(b), sortedInstructions) : "fixed nodes in sorted block are not in the same order"; - blockToNodesMap.put(b, sortedInstructions); - } - - private static List removeProxies(List list) { - List result = new ArrayList<>(); - for (ValueNode n : list) { - if (!(n instanceof ProxyNode)) { - result.add(n); - } - } - return result; - } - - private static List filterSchedulableNodes(List list) { - List result = new ArrayList<>(); - for (ValueNode n : list) { - if (!(n instanceof PhiNode)) { - result.add(n); - } - } - return result; - } - - private static boolean sameOrderForFixedNodes(List fixed, List sorted) { - Iterator fixedIterator = fixed.iterator(); - Iterator sortedIterator = sorted.iterator(); - - while (sortedIterator.hasNext()) { - ValueNode sortedCurrent = sortedIterator.next(); - if (sortedCurrent instanceof FixedNode) { - if (!(fixedIterator.hasNext() && fixedIterator.next() == sortedCurrent)) { - return false; - } - } - } - - while (fixedIterator.hasNext()) { - if (fixedIterator.next() instanceof FixedNode) { - return false; - } - } - - return true; - } - - private static class SortState { - private Block block; - private NodeBitMap visited; - private NodeBitMap beforeLastLocation; - private List sortedInstructions; - private List reads; - - SortState(Block block, NodeBitMap visited, NodeBitMap beforeLastLocation, List sortedInstructions) { - this.block = block; - this.visited = visited; - this.beforeLastLocation = beforeLastLocation; - this.sortedInstructions = sortedInstructions; - this.reads = null; - } - - public Block currentBlock() { - return block; - } - - void markVisited(Node n) { - visited.mark(n); - } - - boolean isVisited(Node n) { - return visited.isMarked(n); - } - - void markBeforeLastLocation(FloatingReadNode n) { - beforeLastLocation.mark(n); - } - - void clearBeforeLastLocation(FloatingReadNode frn) { - beforeLastLocation.clear(frn); - } - - boolean isBeforeLastLocation(FloatingReadNode n) { - return beforeLastLocation.isMarked(n); - } - - void addRead(FloatingReadNode n) { - if (reads == null) { - reads = new ArrayList<>(); - } - reads.add(n); - } - - int readsSize() { - if (reads == null) { - return 0; - } - return reads.size(); - } - - void removeRead(ValueNode i) { - assert reads != null; - reads.remove(i); - } - - List readsSnapshot() { - assert reads != null; - return new ArrayList<>(reads); - } - - List getSortedInstructions() { - return sortedInstructions; - } - - boolean containsInstruction(ValueNode i) { - return sortedInstructions.contains(i); - } - - void addInstruction(ValueNode i) { - sortedInstructions.add(i); - } - } - - /** - * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over - * all inputs. This means that a node is added to the list after all its inputs have been - * processed. - */ - private List sortNodesWithinBlockLatest(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation) { - SortState state = new SortState(b, visited, beforeLastLocation, new ArrayList<>(blockToNodesMap.get(b).size() + 2)); - List instructions = blockToNodesMap.get(b); - - for (ValueNode i : instructions) { - if (i instanceof FloatingReadNode) { - FloatingReadNode frn = (FloatingReadNode) i; - if (!frn.location().getLocationIdentity().isImmutable()) { - state.addRead(frn); - if (nodesFor(b).contains(frn.getLastLocationAccess())) { - assert !state.isBeforeLastLocation(frn); - state.markBeforeLastLocation(frn); - } - } - } - } - - for (ValueNode i : instructions) { - addToLatestSorting(i, state); - } - assert state.readsSize() == 0 : "not all reads are scheduled"; - - // Make sure that last node gets really last (i.e. when a frame state successor hangs off - // it). - List sortedInstructions = state.getSortedInstructions(); - Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1); - if (lastSorted != b.getEndNode()) { - sortedInstructions.remove(b.getEndNode()); - sortedInstructions.add(b.getEndNode()); - } - return sortedInstructions; - } - - private void processKillLocation(Node node, LocationIdentity identity, SortState state) { - for (FloatingReadNode frn : state.readsSnapshot()) { - LocationIdentity readLocation = frn.location().getLocationIdentity(); - assert !readLocation.isImmutable(); - if (frn.getLastLocationAccess() == node) { - assert identity.equals(ANY_LOCATION) || readLocation.equals(identity) || node instanceof MemoryCheckpoint.Multi : "location doesn't match: " + readLocation + ", " + identity; - state.clearBeforeLastLocation(frn); - } else if (!state.isBeforeLastLocation(frn) && (readLocation.equals(identity) || (node != getCFG().graph.start() && ANY_LOCATION.equals(identity)))) { - state.removeRead(frn); - addToLatestSorting(frn, state); - } - } - } - - private void addUnscheduledToLatestSorting(VirtualState state, SortState sortState) { - if (state != null) { - // UnscheduledNodes should never be marked as visited. - if (sortState.isVisited(state)) { - throw new SchedulingError(); - } - - for (Node input : state.inputs()) { - if (input instanceof VirtualState) { - addUnscheduledToLatestSorting((VirtualState) input, sortState); - } else { - addToLatestSorting((ValueNode) input, sortState); - } - } - } - } - - private void addToLatestSorting(ValueNode i, SortState state) { - if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) { - return; - } - - if (i instanceof ProxyNode) { - ProxyNode proxyNode = (ProxyNode) i; - addToLatestSorting(proxyNode.value(), state); - return; - } - - if (i instanceof LoopExitNode) { - LoopExitNode loopExitNode = (LoopExitNode) i; - for (ProxyNode proxy : loopExitNode.proxies()) { - addToLatestSorting(proxy, state); - } - } - - addToLatestSortingHelper(i, state); - } - - private void addToLatestSortingHelper(ValueNode i, SortState state) { - FrameState stateAfter = null; - if (i instanceof StateSplit) { - stateAfter = ((StateSplit) i).stateAfter(); - } - - addInputsToLatestSorting(i, state, stateAfter); - - if (state.readsSize() != 0) { - if (i instanceof MemoryCheckpoint.Single) { - LocationIdentity identity = ((MemoryCheckpoint.Single) i).getLocationIdentity(); - processKillLocation(i, identity, state); - } else if (i instanceof MemoryCheckpoint.Multi) { - for (LocationIdentity identity : ((MemoryCheckpoint.Multi) i).getLocationIdentities()) { - processKillLocation(i, identity, state); - } - } - assert MemoryCheckpoint.TypeAssertion.correctType(i); - } - - addToLatestSorting((ValueNode) i.predecessor(), state); - state.markVisited(i); - addUnscheduledToLatestSorting(stateAfter, state); - - // Now predecessors and inputs are scheduled => we can add this node. - if (!state.containsInstruction(i)) { - state.addInstruction(i); - } - - if (state.readsSize() != 0 && i instanceof FloatingReadNode) { - state.removeRead(i); - } - } - - private void addInputsToLatestSorting(ValueNode i, SortState state, FrameState stateAfter) { - for (Node input : i.inputs()) { - if (input instanceof FrameState) { - if (input != stateAfter) { - addUnscheduledToLatestSorting((FrameState) input, state); - } - } else { - addToLatestSorting((ValueNode) input, state); - } - } - } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Tue Mar 17 12:05:51 2015 +0100 @@ -147,7 +147,7 @@ @Override protected NodeBitMap processBlock(final Block block, final NodeBitMap currentState) { - final List list = schedule.getBlockToNodesMap().get(block); + final List list = schedule.getBlockToNodesMap().get(block); /* * A stateAfter is not valid directly after its associated state split, but @@ -155,78 +155,81 @@ * will be checked at the correct position. */ FrameState pendingStateAfter = null; - for (final ValueNode node : list) { - FrameState stateAfter = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : null; - if (node instanceof FullInfopointNode) { - stateAfter = ((FullInfopointNode) node).getState(); - } + for (final Node node : list) { + if (node instanceof ValueNode) { + FrameState stateAfter = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : null; + if (node instanceof FullInfopointNode) { + stateAfter = ((FullInfopointNode) node).getState(); + } - if (pendingStateAfter != null && node instanceof FixedNode) { - pendingStateAfter.applyToNonVirtual(new NodeClosure() { - @Override - public void apply(Node usage, Node nonVirtualNode) { - assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode + - " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list; + if (pendingStateAfter != null && node instanceof FixedNode) { + pendingStateAfter.applyToNonVirtual(new NodeClosure() { + @Override + public void apply(Node usage, Node nonVirtualNode) { + assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode + + " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list; + } + }); + pendingStateAfter = null; + } + + if (node instanceof AbstractMergeNode) { + // phis aren't scheduled, so they need to be added explicitly + currentState.markAll(((AbstractMergeNode) node).phis()); + if (node instanceof LoopBeginNode) { + // remember the state at the loop entry, it's restored at exits + loopEntryStates.put((LoopBeginNode) node, currentState.copy()); } - }); - pendingStateAfter = null; - } + } else if (node instanceof ProxyNode) { + assert false : "proxy nodes should not be in the schedule"; + } else if (node instanceof LoopExitNode) { + if (graph.hasValueProxies()) { + for (ProxyNode proxy : ((LoopExitNode) node).proxies()) { + for (Node input : proxy.inputs()) { + if (input != proxy.proxyPoint()) { + assert currentState.isMarked(input) : input + " not available at " + proxy + " in block " + block + "\n" + list; + } + } + } - if (node instanceof AbstractMergeNode) { - // phis aren't scheduled, so they need to be added explicitly - currentState.markAll(((AbstractMergeNode) node).phis()); - if (node instanceof LoopBeginNode) { - // remember the state at the loop entry, it's restored at exits - loopEntryStates.put((LoopBeginNode) node, currentState.copy()); - } - } else if (node instanceof ProxyNode) { - assert false : "proxy nodes should not be in the schedule"; - } else if (node instanceof LoopExitNode) { - if (graph.hasValueProxies()) { - for (ProxyNode proxy : ((LoopExitNode) node).proxies()) { - for (Node input : proxy.inputs()) { - if (input != proxy.proxyPoint()) { - assert currentState.isMarked(input) : input + " not available at " + proxy + " in block " + block + "\n" + list; + // loop contents are only accessible via proxies at the exit + currentState.clearAll(); + currentState.markAll(loopEntryStates.get(((LoopExitNode) node).loopBegin())); + } + // Loop proxies aren't scheduled, so they need to be added + // explicitly + currentState.markAll(((LoopExitNode) node).proxies()); + } else { + for (Node input : node.inputs()) { + if (input != stateAfter) { + if (input instanceof FrameState) { + ((FrameState) input).applyToNonVirtual(new VirtualState.NodeClosure() { + @Override + public void apply(Node usage, Node nonVirtual) { + assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list; + } + }); + } else { + assert currentState.isMarked(input) || input instanceof VirtualObjectNode || input instanceof ConstantNode : input + " not available at " + node + + " in block " + block + "\n" + list; } } } - - // loop contents are only accessible via proxies at the exit - currentState.clearAll(); - currentState.markAll(loopEntryStates.get(((LoopExitNode) node).loopBegin())); } - // Loop proxies aren't scheduled, so they need to be added explicitly - currentState.markAll(((LoopExitNode) node).proxies()); - } else { - for (Node input : node.inputs()) { - if (input != stateAfter) { - if (input instanceof FrameState) { - ((FrameState) input).applyToNonVirtual(new VirtualState.NodeClosure() { - @Override - public void apply(Node usage, Node nonVirtual) { - assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list; - } - }); - } else { - assert currentState.isMarked(input) || input instanceof VirtualObjectNode || input instanceof ConstantNode : input + " not available at " + node + - " in block " + block + "\n" + list; - } + if (node instanceof AbstractEndNode) { + AbstractMergeNode merge = ((AbstractEndNode) node).merge(); + for (PhiNode phi : merge.phis()) { + ValueNode phiValue = phi.valueAt((AbstractEndNode) node); + assert phiValue == null || currentState.isMarked(phiValue) || phiValue instanceof ConstantNode : phiValue + " not available at phi " + phi + " / end " + node + + " in block " + block; } } + if (stateAfter != null) { + assert pendingStateAfter == null; + pendingStateAfter = stateAfter; + } + currentState.mark(node); } - if (node instanceof AbstractEndNode) { - AbstractMergeNode merge = ((AbstractEndNode) node).merge(); - for (PhiNode phi : merge.phis()) { - ValueNode phiValue = phi.valueAt((AbstractEndNode) node); - assert phiValue == null || currentState.isMarked(phiValue) || phiValue instanceof ConstantNode : phiValue + " not available at phi " + phi + " / end " + node + - " in block " + block; - } - } - if (stateAfter != null) { - assert pendingStateAfter == null; - pendingStateAfter = stateAfter; - } - currentState.mark(node); } if (pendingStateAfter != null) { pendingStateAfter.applyToNonVirtual(new NodeClosure() { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java Tue Mar 17 12:05:51 2015 +0100 @@ -107,7 +107,11 @@ for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) { // bail out if we compare an object of type klass with == or != (except null checks) ResolvedJavaMethod method = graph.method(); - if (isIllegalUsage(method, cn.getX(), cn.getY(), context.getMetaAccess()) || isIllegalUsage(method, cn.getY(), cn.getX(), context.getMetaAccess())) { + ResolvedJavaType restrictedType = context.getMetaAccess().lookupJavaType(restrictedClass); + + if (method.getDeclaringClass().equals(restrictedType)) { + // Allow violation in methods of the restricted type itself. + } else if (isIllegalUsage(method, cn.getX(), cn.getY(), context.getMetaAccess()) || isIllegalUsage(method, cn.getY(), cn.getX(), context.getMetaAccess())) { throw new VerificationError("Verification of " + restrictedClass.getName() + " usage failed: Comparing " + cn.getX() + " and " + cn.getY() + " in " + method + " must use .equals() for object equality, not '==' or '!='"); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Tue Mar 17 12:05:51 2015 +0100 @@ -140,7 +140,7 @@ } } ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG(); - BlockMap> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap(); + BlockMap> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap(); List blocks = cfg == null ? null : cfg.getBlocks(); writeNodes(graph); writeBlocks(blocks, blockToNodes); @@ -468,11 +468,18 @@ } } - private void writeBlocks(List blocks, BlockMap> blockToNodes) throws IOException { - if (blocks != null) { + private void writeBlocks(List blocks, BlockMap> blockToNodes) throws IOException { + if (blocks != null && blockToNodes != null) { + for (Block block : blocks) { + List nodes = blockToNodes.get(block); + if (nodes == null) { + writeInt(0); + return; + } + } writeInt(blocks.size()); for (Block block : blocks) { - List nodes = blockToNodes.get(block); + List nodes = blockToNodes.get(block); writeInt(block.getId()); writeInt(nodes.size()); for (Node node : nodes) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Mar 17 12:05:51 2015 +0100 @@ -604,7 +604,7 @@ printedNodes = null; } - private void printScheduledBlock(Block block, List nodesFor) { + private void printScheduledBlock(Block block, List nodesFor) { printBlockProlog(block); begin("IR"); out.println("HIR"); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -70,7 +70,7 @@ @Test public void testRead3() { for (Kind kind : KINDS) { - assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.ANY_LOCATION); + assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any()); } } @@ -91,7 +91,7 @@ @Test public void testWrite3() { for (Kind kind : KINDS) { - assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.ANY_LOCATION); + assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.any()); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -79,7 +79,7 @@ @Test public void testRead3() { for (Kind kind : KINDS) { - assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.ANY_LOCATION); + assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.any()); } } @@ -100,7 +100,7 @@ @Test public void testWrite3() { for (Kind kind : KINDS) { - assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.ANY_LOCATION); + assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.any()); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Tue Mar 17 12:05:51 2015 +0100 @@ -235,8 +235,7 @@ SnippetTemplate template = template(args); Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, args); - template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, tool, args); - GraphUtil.killWithUnusedFloatingInputs(unbox); + template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, args); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Tue Mar 17 12:05:51 2015 +0100 @@ -100,7 +100,9 @@ if (res instanceof UnsafeCopyNode) { UnsafeCopyNode copy = (UnsafeCopyNode) res; UnsafeLoadNode value = b.append(new UnsafeLoadNode(copy.sourceObject(), copy.sourceOffset(), copy.accessKind(), copy.getLocationIdentity())); - b.append(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity())); + UnsafeStoreNode unsafeStore = new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity()); + b.append(unsafeStore); + unsafeStore.setStateAfter(b.createStateAfter()); return true; } else if (res instanceof ForeignCallNode) { ForeignCallNode foreign = (ForeignCallNode) res; @@ -115,6 +117,13 @@ assert res.getKind().getStackKind() == Kind.Void; } + if (res instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) res; + if (stateSplit.stateAfter() == null) { + stateSplit.setStateAfter(b.createStateAfter()); + } + } + return true; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Tue Mar 17 12:05:51 2015 +0100 @@ -590,7 +590,7 @@ protected ConstantLocationNode createFieldLocation(StructuredGraph graph, ResolvedJavaField field, boolean initialization) { int offset = fieldOffset(field); if (offset >= 0) { - LocationIdentity loc = initialization ? initLocationIdentity() : field; + LocationIdentity loc = initialization ? initLocationIdentity() : field.getLocationIdentity(); return graph.unique(new ConstantLocationNode(loc, offset)); } else { return null; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -444,7 +444,7 @@ } else if (usage instanceof UnboxNode) { UnboxNode unbox = (UnboxNode) usage; unbox.replaceAtUsages(intrinsifiedNode); - graph.removeFloating(unbox); + graph.removeFixed(unbox); Debug.log("%s: Removed an UnboxNode", Debug.contextSnapshot(JavaMethod.class)); } else if (usage instanceof UnsafeStoreNode) { UnsafeStoreNode store = (UnsafeStoreNode) usage; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Mar 17 12:05:51 2015 +0100 @@ -1027,8 +1027,8 @@ if (replacee instanceof MemoryCheckpoint.Single) { // check if some node in snippet graph also kills the same location LocationIdentity locationIdentity = ((MemoryCheckpoint.Single) replacee).getLocationIdentity(); - if (locationIdentity.equals(ANY_LOCATION)) { - assert !(memoryMap.getLastLocationAccess(ANY_LOCATION) instanceof MemoryAnchorNode) : replacee + " kills ANY_LOCATION, but snippet does not"; + if (locationIdentity.isAny()) { + assert !(memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) : replacee + " kills ANY_LOCATION, but snippet does not"; } assert kills.contains(locationIdentity) : replacee + " kills " + locationIdentity + ", but snippet doesn't contain a kill to this location"; return true; @@ -1038,12 +1038,12 @@ Debug.log("WARNING: %s is not a MemoryCheckpoint, but the snippet graph contains kills (%s). You might want %s to be a MemoryCheckpoint", replacee, kills, replacee); // remove ANY_LOCATION if it's just a kill by the start node - if (memoryMap.getLastLocationAccess(ANY_LOCATION) instanceof MemoryAnchorNode) { - kills.remove(ANY_LOCATION); + if (memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) { + kills.remove(any()); } // node can only lower to a ANY_LOCATION kill if the replacee also kills ANY_LOCATION - assert !kills.contains(ANY_LOCATION) : "snippet graph contains a kill to ANY_LOCATION, but replacee (" + replacee + ") doesn't kill ANY_LOCATION. kills: " + kills; + assert !kills.contains(any()) : "snippet graph contains a kill to ANY_LOCATION, but replacee (" + replacee + ") doesn't kill ANY_LOCATION. kills: " + kills; /* * kills to other locations than ANY_LOCATION can be still inserted if there aren't any diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Tue Mar 17 12:05:51 2015 +0100 @@ -108,7 +108,9 @@ Class javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass(); r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) { - b.push(Kind.Boolean.getStackKind(), b.append(new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.ANY_LOCATION))); + CompareAndSwapNode compareAndSwap = new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any()); + b.push(Kind.Boolean.getStackKind(), b.append(compareAndSwap)); + compareAndSwap.setStateAfter(b.createStateAfter()); return true; } }); @@ -116,14 +118,18 @@ if (getAndSetEnabled(arch)) { r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) { - b.push(kind.getStackKind(), b.append(new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION))); + AtomicReadAndWriteNode atomicReadWrite = new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any()); + b.push(kind.getStackKind(), b.append(atomicReadWrite)); + atomicReadWrite.setStateAfter(b.createStateAfter()); return true; } }); if (kind != Kind.Object) { r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode delta) { - b.push(kind.getStackKind(), b.append(new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.ANY_LOCATION))); + AtomicReadAndAddNode atomicReadAdd = new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any()); + b.push(kind.getStackKind(), b.append(atomicReadAdd)); + atomicReadAdd.setStateAfter(b.createStateAfter()); return true; } }); @@ -347,7 +353,9 @@ r.register1("", Receiver.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object) { if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) { - b.append(new RegisterFinalizerNode(object)); + RegisterFinalizerNode registerFinalizer = new RegisterFinalizerNode(object); + b.append(registerFinalizer); + registerFinalizer.setStateAfter(b.createStateAfter()); } return true; } @@ -359,7 +367,7 @@ r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) { ValueNode nullCheckedType = nullCheckedValue(b, type); - LogicNode condition = b.append(new InstanceOfDynamicNode(nullCheckedType, object).canonical(null, nullCheckedType, object)); + LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), nullCheckedType, object)); b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null))); return true; } @@ -397,7 +405,7 @@ for (Class c : new Class[]{Node.class, NodeList.class}) { r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset) { - ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION)); + ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any())); boolean exactType = false; boolean nonNull = false; b.push(Kind.Object, b.append(new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull))); @@ -406,7 +414,9 @@ }); r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset, ValueNode value) { - b.append(new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION)); + UnsafeStoreNode unsafeStore = new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any()); + b.append(unsafeStore); + unsafeStore.setStateAfter(b.createStateAfter()); return true; } }); @@ -489,7 +499,7 @@ if (isVolatile) { b.append(new MembarNode(JMM_PRE_VOLATILE_READ)); } - b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.ANY_LOCATION))); + b.push(returnKind.getStackKind(), b.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any()))); if (isVolatile) { b.append(new MembarNode(JMM_POST_VOLATILE_READ)); } @@ -516,7 +526,9 @@ if (isVolatile) { b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE)); } - b.append(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION)); + UnsafeStoreNode unsafeStore = new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.any()); + b.append(unsafeStore); + unsafeStore.setStateAfter(b.createStateAfter()); if (isVolatile) { b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE)); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Tue Mar 17 12:05:51 2015 +0100 @@ -102,7 +102,7 @@ Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass())); LocationNode location; if (args.length == 2) { - location = makeLocation(b, args[1], ANY_LOCATION); + location = makeLocation(b, args[1], any()); } else { location = makeLocation(b, args[1], args[2]); } @@ -112,7 +112,7 @@ case READ_HEAP: { assert args.length == 3; Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass())); - LocationNode location = makeLocation(b, args[1], ANY_LOCATION); + LocationNode location = makeLocation(b, args[1], any()); BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant()); b.push(returnStackKind, readOp(b, readKind, args[0], location, barrierType, true)); break; @@ -125,7 +125,7 @@ Kind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass())); LocationNode location; if (args.length == 3) { - location = makeLocation(b, args[1], LocationIdentity.ANY_LOCATION); + location = makeLocation(b, args[1], LocationIdentity.any()); } else { location = makeLocation(b, args[1], args[3]); } @@ -246,7 +246,9 @@ final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE); final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED); final boolean initialize = (op == Opcode.INITIALIZE); - b.append(new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize)); + JavaWriteNode writeNode = new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize); + b.append(writeNode); + writeNode.setStateAfter(b.createStateAfter()); } public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, LocationIdentity locationIdentity) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -62,7 +62,7 @@ } public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } protected void replaceSnippetInvokes(StructuredGraph snippetGraph) { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Mar 17 12:05:51 2015 +0100 @@ -344,18 +344,22 @@ } public void notifyCompilationFailed(Throwable t) { - if (!(t instanceof BailoutException) || ((BailoutException) t).isPermanent()) { + if (t instanceof BailoutException && !((BailoutException) t).isPermanent()) { + /* + * Non permanent bailouts are expected cases. A non permanent bailout would be for + * example class redefinition during code installation. As opposed to permanent + * bailouts, non permanent bailouts will trigger recompilation and are not considered a + * failure state. + */ + } else { compilationPolicy.recordCompilationFailure(t); if (TruffleCompilationExceptionsAreThrown.getValue()) { throw new OptimizationFailedException(t, this); } - } - - if (t instanceof BailoutException) { - // Bailout => move on. - } else if (TruffleCompilationExceptionsAreFatal.getValue()) { - t.printStackTrace(OUT); - System.exit(-1); + if (TruffleCompilationExceptionsAreFatal.getValue()) { + t.printStackTrace(OUT); + System.exit(-1); + } } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Mar 17 12:05:51 2015 +0100 @@ -204,6 +204,7 @@ if (replacements != null && (replacements.getMethodSubstitutionMethod(original) != null || replacements.getMacroSubstitution(original) != null)) { return null; } + assert !builder.parsingReplacement(); if (original.equals(callSiteProxyMethod)) { ValueNode arg1 = arguments[0]; if (!arg1.isConstant()) { @@ -221,10 +222,10 @@ if (decision != null && decision.isInline()) { inlining.push(decision); builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption())); - return new InlineInfo(callInlinedMethod, false); + return new InlineInfo(callInlinedMethod, false, false); } } - return new InlineInfo(original, false); + return new InlineInfo(original, false, false); } public void postInline(ResolvedJavaMethod inlinedTargetMethod) { @@ -261,6 +262,7 @@ plugins.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining(), providers.getReplacements())); plugins.setLoopExplosionPlugin(new LoopExplosionPlugin()); TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), newConfig.getPlugins().getInvocationPlugins()); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations, null).apply(graph); Debug.dump(graph, "After FastPE"); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Mar 17 12:05:51 2015 +0100 @@ -66,8 +66,17 @@ private final TruffleCache truffleCache; private final GraalTruffleCompilationListener compilationNotify; - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class, - VirtualMachineError.class, ClassCastException.class}; + // @formatter:off + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{ + UnexpectedResultException.class, + SlowPathException.class, + ArithmeticException.class, + IllegalArgumentException.class, + VirtualMachineError.class, + StringIndexOutOfBoundsException.class, + ClassCastException.class + }; + // @formatter:off public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java Tue Mar 17 12:05:51 2015 +0100 @@ -29,7 +29,7 @@ /** * A {@link LocationIdentity} wrapping an object. */ -public final class ObjectLocationIdentity implements LocationIdentity { +public final class ObjectLocationIdentity extends LocationIdentity { private JavaConstant object; @@ -53,6 +53,7 @@ } private ObjectLocationIdentity(JavaConstant object) { + super(false); this.object = object; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -60,7 +60,7 @@ ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX); LocationIdentity locationIdentity; if (locationArgument.isNullConstant()) { - locationIdentity = LocationIdentity.ANY_LOCATION; + locationIdentity = LocationIdentity.any(); } else { locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant()); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -57,7 +57,7 @@ ValueNode valueArgument = arguments.get(VALUE_ARGUMENT_INDEX); LocationIdentity locationIdentity; if (locationArgument.isNullConstant()) { - locationIdentity = LocationIdentity.ANY_LOCATION; + locationIdentity = LocationIdentity.any(); } else { locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant()); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Tue Mar 17 12:05:51 2015 +0100 @@ -337,7 +337,7 @@ if (location.isConstant()) { LocationIdentity locationIdentity; if (location.isNullConstant()) { - locationIdentity = LocationIdentity.ANY_LOCATION; + locationIdentity = LocationIdentity.any(); } else { locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant()); } @@ -363,12 +363,14 @@ if (locationArgument.isConstant()) { LocationIdentity locationIdentity; if (locationArgument.isNullConstant()) { - locationIdentity = LocationIdentity.ANY_LOCATION; + locationIdentity = LocationIdentity.any(); } else { locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant()); } - b.append(new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null)); + UnsafeStoreNode unsafeStore = new UnsafeStoreNode(object, offset, value, kind, locationIdentity, null); + b.append(unsafeStore); + unsafeStore.setStateAfter(b.createStateAfter()); return true; } // TODO: should we throw GraalInternalError.shouldNotReachHere() here? diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Tue Mar 17 12:05:51 2015 +0100 @@ -79,7 +79,7 @@ schedule = null; cfg = ControlFlowGraph.compute(graph, true, true, false, false); } else { - schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST); + schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST); schedule.apply(graph, false); cfg = schedule.getCFG(); } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Tue Mar 17 12:05:51 2015 +0100 @@ -83,7 +83,7 @@ if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode instance = (VirtualInstanceNode) virtual; for (int i = 0; i < instance.entryCount(); i++) { - readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(i)); + readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation), values.get(i)); } } } @@ -133,7 +133,7 @@ readCache.clear(); } - public void killReadCache(ResolvedJavaField identity) { + public void killReadCache(LocationIdentity identity) { Iterator> iter = readCache.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Tue Mar 17 12:05:51 2015 +0100 @@ -89,7 +89,7 @@ private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) { if (!store.isVolatile()) { ValueNode object = GraphUtil.unproxify(store.object()); - ValueNode cachedValue = state.getReadCache(object, store.field(), this); + ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), this); ValueNode value = getScalarAlias(store.value()); boolean result = false; @@ -97,37 +97,37 @@ effects.deleteNode(store); result = true; } - state.killReadCache(store.field()); - state.addReadCache(object, store.field(), value, this); + state.killReadCache(store.field().getLocationIdentity()); + state.addReadCache(object, store.field().getLocationIdentity(), value, this); return result; } else { - processIdentity(state, ANY_LOCATION); + processIdentity(state, any()); } return false; } private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) { - if (!load.isVolatile()) { + if (load.isVolatile()) { + processIdentity(state, any()); + } else { ValueNode object = GraphUtil.unproxify(load.object()); - ValueNode cachedValue = state.getReadCache(object, load.field(), this); + ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), this); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); addScalarAlias(load, cachedValue); return true; } else { - state.addReadCache(object, load.field(), load, this); + state.addReadCache(object, load.field().getLocationIdentity(), load, this); } - } else { - processIdentity(state, ANY_LOCATION); } return false; } private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) { - if (identity instanceof ResolvedJavaField) { - state.killReadCache((ResolvedJavaField) identity); - } else if (identity.equals(ANY_LOCATION)) { + if (identity.isAny()) { state.killReadCache(); + } else { + state.killReadCache(identity); } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Mar 17 12:05:51 2015 +0100 @@ -119,7 +119,7 @@ @Override protected boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode) { boolean isMarked = usages.isMarked(node); - if (isMarked || node instanceof VirtualizableRoot) { + if ((isMarked && node instanceof ValueNode) || node instanceof VirtualizableRoot) { VirtualUtil.trace("[[%s]] ", node); FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next(); return processNode((ValueNode) node, nextFixedNode, state, effects, isMarked); diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Tue Mar 17 12:05:51 2015 +0100 @@ -57,10 +57,10 @@ if (node instanceof AccessFieldNode) { AccessFieldNode access = (AccessFieldNode) node; if (access.isVolatile()) { - processIdentity(state, ANY_LOCATION); + processIdentity(state, any()); } else { ValueNode object = GraphUtil.unproxify(access.object()); - LoadCacheEntry identifier = new LoadCacheEntry(object, access.field()); + LoadCacheEntry identifier = new LoadCacheEntry(object, access.field().getLocationIdentity()); ValueNode cachedValue = state.getCacheEntry(identifier); if (node instanceof LoadFieldNode) { if (cachedValue != null && access.stamp().isCompatible(cachedValue.stamp())) { @@ -78,7 +78,7 @@ effects.deleteNode(store); deleted = true; } - state.killReadCache(store.field()); + state.killReadCache(store.field().getLocationIdentity()); state.addCacheEntry(identifier, value); } } @@ -119,7 +119,7 @@ } else if (node instanceof UnsafeAccessNode) { if (node instanceof UnsafeLoadNode) { UnsafeLoadNode load = (UnsafeLoadNode) node; - if (load.offset().isConstant() && !load.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION)) { + if (load.offset().isConstant() && !load.getLocationIdentity().equals(LocationIdentity.any())) { ValueNode object = GraphUtil.unproxify(load.object()); UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity()); ValueNode cachedValue = state.getCacheEntry(identifier); @@ -134,7 +134,7 @@ } else { assert node instanceof UnsafeStoreNode; UnsafeStoreNode write = (UnsafeStoreNode) node; - if (write.offset().isConstant() && !write.getLocationIdentity().equals(LocationIdentity.ANY_LOCATION)) { + if (write.offset().isConstant() && !write.getLocationIdentity().equals(LocationIdentity.any())) { ValueNode object = GraphUtil.unproxify(write.object()); UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity()); ValueNode cachedValue = state.getCacheEntry(identifier); @@ -162,7 +162,7 @@ } private static void processIdentity(ReadEliminationBlockState state, LocationIdentity identity) { - if (identity.equals(ANY_LOCATION)) { + if (identity.isAny()) { state.killReadCache(); return; } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -74,7 +74,7 @@ return identity; } // We do not know our actual location identity yet, so be conservative. - return ANY_LOCATION; + return any(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Tue Mar 17 12:05:51 2015 +0100 @@ -380,11 +380,7 @@ @Override public Probe getProbe() { - try { - return probeNode.getProbe(); - } catch (IllegalStateException e) { - throw new IllegalStateException("Cannot call getProbe() on a wrapper that has no probe"); - } + return probeNode.getProbe(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java Tue Mar 17 12:05:51 2015 +0100 @@ -119,11 +119,7 @@ @Override public Probe getProbe() { - try { - return probeNode.getProbe(); - } catch (IllegalStateException e) { - throw new IllegalStateException("Cannot call getProbe() on a wrapper that has no probe"); - } + return probeNode.getProbe(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java Tue Mar 17 12:05:51 2015 +0100 @@ -58,12 +58,7 @@ /** * Wrapper not assignable to the parent's child field. */ - WRAPPER_TYPE("Wrapper not assignable to parent's child field"), - - /** - * Attempt to \"probe lite\" an already probed node. - */ - LITE_VIOLATION("Attempt to \"probe lite\" an already probed node"); + WRAPPER_TYPE("Wrapper not assignable to parent's child field"); final String message; diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -33,9 +33,20 @@ import com.oracle.truffle.api.source.*; /** - * Implementation interfaces and classes for attaching {@link Probe}s to {@link WrapperNode}s. + * Implementation class & interface for enabling the attachment of {@linkplain Probe Probes} to + * Truffle ASTs. + *

+ * A {@link ProbeNode} is the head of a chain of nodes acting on behalf of {@linkplain Instrument + * instruments}. It is attached to an AST as a child of a guest-language-specific + * {@link WrapperNode} node. + *

+ * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument instruments} + * will be cloned along with the {@link WrapperNode} to which it is attached. An instance of + * {@link Probe} represents abstractly the instrumentation at a particular location in a GL AST, + * tracks the clones of the chain, and keeps the instrumentation attached to the clones consistent. */ -public abstract class ProbeNode extends Node implements TruffleEvents, InstrumentationNode { +@NodeInfo(cost = NodeCost.NONE) +public final class ProbeNode extends Node implements TruffleEvents, InstrumentationNode { /** * A node that can be inserted into a Truffle AST, and which enables {@linkplain Instrument @@ -91,8 +102,7 @@ Node getChild(); /** - * Gets the {@link Probe} responsible for installing this wrapper; none if the wrapper - * installed via {@linkplain Node#probeLite(ASTInstrumentListener) "lite-Probing"}. + * Gets the {@link Probe} responsible for installing this wrapper. */ Probe getProbe(); @@ -100,7 +110,6 @@ * Implementation support for completing a newly created wrapper node. */ void insertProbe(ProbeNode probeNode); - } /** @@ -109,202 +118,99 @@ */ public static Probe insertProbe(WrapperNode wrapper) { final SourceSection sourceSection = wrapper.getChild().getSourceSection(); - final ProbeFullNode probeFullNode = new ProbeFullNode(); // private constructor - final Probe probe = new Probe(probeFullNode, sourceSection); // package private access - probeFullNode.setProbe(probe); - wrapper.insertProbe(probeFullNode); - return probe; + final ProbeNode probeNode = new ProbeNode(); // private constructor + probeNode.probe = new Probe(probeNode, sourceSection); // package private access + wrapper.insertProbe(probeNode); + return probeNode.probe; } + // Never changed once set. + @CompilationFinal Probe probe = null; /** - * Creates a new {@link ProbeLiteNode} associated with, and attached to, a Guest Language - * specific instance of {@link WrapperNode}. + * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in chain. */ - public static void insertProbeLite(WrapperNode wrapper, ASTInstrumentListener instrumentListener) { - final ProbeLiteNode probeLiteNode = new ProbeLiteNode(instrumentListener); - wrapper.insertProbe(probeLiteNode); - } + @Child protected AbstractInstrumentNode firstInstrument; @Override public boolean isInstrumentable() { return false; } + @Override + public Node copy() { + Node node = super.copy(); + probe.registerProbeNodeClone((ProbeNode) node); + return node; + } + /** * @return the {@link Probe} permanently associated with this {@link ProbeNode}. - * - * @throws IllegalStateException if this location was "lite-Probed" */ - public abstract Probe getProbe() throws IllegalStateException; + public Probe getProbe() { + return probe; + } + + public void enter(Node node, VirtualFrame vFrame) { + this.probe.checkProbeUnchanged(); + final SyntaxTagTrap trap = probe.getTrap(); + if (trap != null) { + trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), vFrame.materialize()); + } + if (firstInstrument != null) { + firstInstrument.enter(node, vFrame); + } + } + + public void returnVoid(Node node, VirtualFrame vFrame) { + this.probe.checkProbeUnchanged(); + if (firstInstrument != null) { + firstInstrument.returnVoid(node, vFrame); + } + } + + public void returnValue(Node node, VirtualFrame vFrame, Object result) { + this.probe.checkProbeUnchanged(); + if (firstInstrument != null) { + firstInstrument.returnValue(node, vFrame, result); + } + } + + public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { + this.probe.checkProbeUnchanged(); + if (firstInstrument != null) { + firstInstrument.returnExceptional(node, vFrame, exception); + } + } + + public String instrumentationInfo() { + return "Standard probe"; + } /** * Adds an {@link AbstractInstrumentNode} to this chain. - * - * @throws IllegalStateException if at a "lite-Probed" location. */ - abstract void addInstrument(Instrument instrument); + @TruffleBoundary + void addInstrument(Instrument instrument) { + assert instrument.getProbe() == probe; + // The existing chain of nodes may be empty + // Attach the modified chain. + firstInstrument = insert(instrument.addToChain(firstInstrument)); + } /** * Removes an instrument from this chain of instruments. * - * @throws IllegalStateException if at a "lite-Probed" location. * @throws RuntimeException if no matching instrument is found, */ - abstract void removeInstrument(Instrument instrument); - - /** - * Implementation class & interfaces for enabling the attachment of {@linkplain Probe Probes} to - * Truffle ASTs. - *

- * Head of a chain of nodes acting on behalf of {@linkplain Instrument instruments}, attached to - * a Guest Language (GL) AST as a child of a GL-specific {@link WrapperNode} node. - *

- * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument - * instruments} will be cloned along with the {@link WrapperNode} to which it is attached. An - * instance of {@link Probe} represents abstractly the instrumentation at a particular location - * in a GL AST, tracks the clones of the chain, and keeps the instrumentation attached to the - * clones consistent. - */ - @NodeInfo(cost = NodeCost.NONE) - private static final class ProbeFullNode extends ProbeNode { - - /** - * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in - * chain. - */ - @Child protected AbstractInstrumentNode firstInstrument; - - // Never changed once set. - @CompilationFinal private Probe probe = null; - - private ProbeFullNode() { - this.firstInstrument = null; - } - - @Override - public Probe getProbe() throws IllegalStateException { - return probe; - } - - @Override - public Node copy() { - Node node = super.copy(); - probe.registerProbeNodeClone((ProbeNode) node); - return node; - } - - private void setProbe(Probe probe) { - this.probe = probe; - } - - @Override - @TruffleBoundary - void addInstrument(Instrument instrument) { - assert instrument.getProbe() == probe; - // The existing chain of nodes may be empty - // Attach the modified chain. - firstInstrument = insert(instrument.addToChain(firstInstrument)); - } - - @Override - @TruffleBoundary - void removeInstrument(Instrument instrument) { - assert instrument.getProbe() == probe; - final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument); - if (modifiedChain == null) { - firstInstrument = null; - } else { - firstInstrument = insert(modifiedChain); - } - } - - public void enter(Node node, VirtualFrame vFrame) { - this.probe.checkProbeUnchanged(); - final SyntaxTagTrap trap = probe.getTrap(); - if (trap != null) { - trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), vFrame.materialize()); - } - if (firstInstrument != null) { - firstInstrument.enter(node, vFrame); - } - } - - public void returnVoid(Node node, VirtualFrame vFrame) { - this.probe.checkProbeUnchanged(); - if (firstInstrument != null) { - firstInstrument.returnVoid(node, vFrame); - } - } - - public void returnValue(Node node, VirtualFrame vFrame, Object result) { - this.probe.checkProbeUnchanged(); - if (firstInstrument != null) { - firstInstrument.returnValue(node, vFrame, result); - } - } - - public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - this.probe.checkProbeUnchanged(); - if (firstInstrument != null) { - firstInstrument.returnExceptional(node, vFrame, exception); - } - } - - public String instrumentationInfo() { - return "Standard probe"; + @TruffleBoundary + void removeInstrument(Instrument instrument) { + assert instrument.getProbe() == probe; + final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument); + if (modifiedChain == null) { + firstInstrument = null; + } else { + firstInstrument = insert(modifiedChain); } } - /** - * Implementation of a probe that only ever has a single "instrument" associated with it. No - * {@link Instrument} is ever created; instead this method simply delegates the various enter - * and return events to a {@link TruffleEvents} passed in during construction. - */ - @NodeInfo(cost = NodeCost.NONE) - private static final class ProbeLiteNode extends ProbeNode { - - private final ASTInstrumentListener instrumentListener; - - private ProbeLiteNode(ASTInstrumentListener eventListener) { - this.instrumentListener = eventListener; - } - - @Override - public Probe getProbe() throws IllegalStateException { - throw new IllegalStateException("\"lite-Probed\" nodes have no explicit Probe"); - } - - @Override - @TruffleBoundary - void addInstrument(Instrument instrument) { - throw new IllegalStateException("Instruments may not be added at a \"lite-probed\" location"); - } - - @Override - @TruffleBoundary - void removeInstrument(Instrument instrument) { - throw new IllegalStateException("Instruments may not be removed at a \"lite-probed\" location"); - } - - public void enter(Node node, VirtualFrame vFrame) { - instrumentListener.enter(getProbe(), node, vFrame); - } - - public void returnVoid(Node node, VirtualFrame vFrame) { - instrumentListener.returnVoid(getProbe(), node, vFrame); - } - - public void returnValue(Node node, VirtualFrame vFrame, Object result) { - instrumentListener.returnValue(getProbe(), node, vFrame, result); - } - - public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - instrumentListener.returnExceptional(getProbe(), node, vFrame, exception); - } - - public String instrumentationInfo() { - return "\"Lite\" probe"; - } - - } } diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue Mar 17 12:05:51 2015 +0100 @@ -497,61 +497,6 @@ } /** - * Enables "one-shot", unmodifiable {@linkplain Instrument instrumentation} of a node, where the - * node is presumed to be part of a well-formed Truffle AST that is not being executed. - *

- * Modifies the AST by inserting a {@linkplain WrapperNode wrapper node} between the node and - * its parent; the wrapper node must be provided by implementations of - * {@link #createWrapperNode()}. - *

- * Unlike {@link #probe()}, once {@link #probeLite(ASTInstrumentListener)} is called at a node, - * no additional probing can be added and no additional instrumentation can be attached. - *

- * This restricted form of instrumentation is intended for special cases where only one kind of - * instrumentation is desired, and for which performance is a concern - * - * @param instrumentListener - * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged - */ - public final void probeLite(ASTInstrumentListener instrumentListener) { - - if (this instanceof WrapperNode) { - throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null); - } - - if (parent == null) { - throw new ProbeException(ProbeFailure.Reason.NO_PARENT, null, this, null); - } - - if (parent instanceof WrapperNode) { - throw new ProbeException(ProbeFailure.Reason.LITE_VIOLATION, null, this, null); - } - - if (!isInstrumentable()) { - throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, this, null); - } - - // Create a new wrapper/probe with this node as its child. - final WrapperNode wrapper = createWrapperNode(); - - if (wrapper == null || !(wrapper instanceof Node)) { - throw new ProbeException(ProbeFailure.Reason.NO_WRAPPER, parent, this, wrapper); - } - - final Node wrapperNode = (Node) wrapper; - - if (!this.isSafelyReplaceableBy(wrapperNode)) { - throw new ProbeException(ProbeFailure.Reason.WRAPPER_TYPE, parent, this, wrapper); - } - - // Connect it to a Probe - ProbeNode.insertProbeLite(wrapper, instrumentListener); - - // Replace this node in the AST with the wrapper - this.replace(wrapperNode); - } - - /** * Converts this node to a textual representation useful for debugging. */ @Override diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -72,11 +72,7 @@ } public Probe getProbe() { - try { - return probeNode.getProbe(); - } catch (IllegalStateException e) { - throw new IllegalStateException("A lite-Probed wrapper has no explicit Probe"); - } + return probeNode.getProbe(); } public Node getChild() { diff -r 8e316bc46018 -r 825f5c7468bd graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java Tue Mar 17 12:05:11 2015 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java Tue Mar 17 12:05:51 2015 +0100 @@ -65,11 +65,7 @@ } public Probe getProbe() { - try { - return probeNode.getProbe(); - } catch (IllegalStateException e) { - throw new IllegalStateException("A lite-Probed wrapper has no explicit Probe"); - } + return probeNode.getProbe(); } @Override diff -r 8e316bc46018 -r 825f5c7468bd mxtool/mx.py --- a/mxtool/mx.py Tue Mar 17 12:05:11 2015 +0100 +++ b/mxtool/mx.py Tue Mar 17 12:05:51 2015 +0100 @@ -2823,13 +2823,16 @@ else: # Using just SC_ARG_MAX without extra downwards adjustment # results in "[Errno 7] Argument list too long" on MacOS. - syslimit = os.sysconf('SC_ARG_MAX') - 20000 + commandLinePrefixAllowance -= 20000 + syslimit = os.sysconf('SC_ARG_MAX') if syslimit == -1: syslimit = 262144 # we could use sys.maxint but we prefer a more robust smaller value limit = syslimit - commandLinePrefixAllowance + assert limit > 0 for i in range(len(files)): path = pathFunction(files[i]) size = len(path) + 1 + assert size < limit if chunkSize + size < limit: chunkSize += size else: @@ -4172,6 +4175,31 @@ out.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'}) out.element('description', data='Builds, tests, and runs the project ' + p.name + '.') out.element('import', {'file' : 'nbproject/build-impl.xml'}) + out.open('target', {'name' : '-post-init'}) + out.open('pathconvert', {'property' : 'comma.javac.classpath', 'pathsep' : ','}) + out.element('path', {'path' : '${javac.classpath}'}) + out.close('pathconvert') + + out.open('restrict', {'id' : 'missing.javac.classpath'}) + out.element('filelist', {'dir' : '${basedir}', 'files' : '${comma.javac.classpath}'}) + out.open('not') + out.element('exists') + out.close('not') + out.close('restrict') + + out.element('property', {'name' : 'missing.javac.classpath', 'refid' : 'missing.javac.classpath'}) + + out.open('condition', {'property' : 'no.dependencies', 'value' : 'true'}) + out.element('equals', {'arg1' : '${missing.javac.classpath}', 'arg2' : ''}) + out.close('condition') + + out.element('property', {'name' : 'no.dependencies', 'value' : 'false'}) + + out.open('condition', {'property' : 'no.deps'}) + out.element('equals', {'arg1' : '${no.dependencies}', 'arg2' : 'true'}) + out.close('condition') + + out.close('target') out.open('target', {'name' : '-post-compile'}) out.open('exec', {'executable' : sys.executable}) out.element('env', {'key' : 'JAVA_HOME', 'value' : jdk.jdk})