# HG changeset patch # User Doug Simon # Date 1426590804 -3600 # Node ID 87c62a38f843b8ac9c2a1198724f0c0f72c792a8 # Parent b950967f74c7a1f886089698b4e5056dbe69d9ff# Parent ab898f9f9c3cc135c6b010062a59726ff92a8e78 Merge. diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallsProvider.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/BitOpsTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue Mar 17 12:13:24 2015 +0100 @@ -307,7 +307,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(); @@ -327,7 +326,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Tue Mar 17 12:13:24 2015 +0100 @@ -182,9 +182,7 @@ NodeClass snc = superNodeClass; while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { - assert !containsId(this.iterableId, snc.iterableIds); - snc.iterableIds = Arrays.copyOf(snc.iterableIds, snc.iterableIds.length + 1); - snc.iterableIds[snc.iterableIds.length - 1] = this.iterableId; + snc.addIterableId(iterableId); snc = snc.superNodeClass; } @@ -195,6 +193,23 @@ this.iterableIds = null; } nodeIterableCount = Debug.metric("NodeIterable_%s", clazz); + assert verifyIterableIds(); + } + + private synchronized void addIterableId(int newIterableId) { + assert !containsId(newIterableId, iterableIds); + int[] copy = Arrays.copyOf(iterableIds, iterableIds.length + 1); + copy[iterableIds.length] = newIterableId; + iterableIds = copy; + } + + private boolean verifyIterableIds() { + NodeClass snc = superNodeClass; + while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { + assert containsId(iterableId, snc.iterableIds); + snc = snc.superNodeClass; + } + return true; } private static boolean containsId(int iterableId, int[] iterableIds) { diff -r b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderPlugin.java diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java Tue Mar 17 12:13:24 2015 +0100 @@ -34,22 +34,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"; } } diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstant.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Tue Mar 17 12:13:24 2015 +0100 @@ -109,13 +109,17 @@ Registration r = new Registration(plugins, 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Tue Mar 17 12:13:24 2015 +0100 @@ -47,20 +47,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -57,7 +57,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -49,7 +49,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -66,6 +66,6 @@ public static native long saveAllRegisters(); public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } } diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -141,7 +141,7 @@ if (elementKind != null) { return NamedLocationIdentity.getArrayLocation(elementKind); } - return ANY_LOCATION; + return any(); } @NodeIntrinsic diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -119,7 +119,7 @@ if (elementKind != null) { return NamedLocationIdentity.getArrayLocation(elementKind); } - return ANY_LOCATION; + return any(); } @NodeIntrinsic diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Tue Mar 17 12:13:24 2015 +0100 @@ -357,7 +357,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)); @@ -365,7 +365,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) { @@ -869,7 +869,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); @@ -877,7 +877,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); } @@ -902,16 +902,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); @@ -930,9 +926,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); @@ -1292,8 +1288,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue Mar 17 12:13:24 2015 +0100 @@ -349,10 +349,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()) { @@ -758,8 +757,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 @@ -975,8 +976,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())); } /** @@ -1132,7 +1135,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; } @@ -1216,8 +1219,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); @@ -1303,6 +1307,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; } @@ -1353,22 +1358,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 @@ -1923,11 +1928,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(); } } @@ -1983,10 +1987,6 @@ } } - private boolean isBlockEnd(Node n) { - return n instanceof ControlSplitNode || n instanceof ControlSinkNode; - } - @Override protected void iterateBytecodesForBlock(BciBlock block) { if (block.isLoopHeader && !explodeLoops) { @@ -2055,26 +2055,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) { @@ -2388,8 +2377,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/LocalLiveness.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:49 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -107,7 +107,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -154,7 +154,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -44,6 +44,6 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } } diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -59,7 +59,7 @@ } public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } public void lower(LoweringTool tool) { diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -45,7 +45,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -44,7 +44,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -43,7 +43,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -58,7 +58,7 @@ @Override public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } @Override diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRBuilder.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Tue Mar 17 12:13:24 2015 +0100 @@ -99,7 +99,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; @@ -114,6 +116,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Tue Mar 17 12:13:24 2015 +0100 @@ -449,7 +449,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Tue Mar 17 12:13:24 2015 +0100 @@ -106,7 +106,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; } }); @@ -114,14 +116,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; } }); @@ -345,7 +351,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; } @@ -357,7 +365,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; } @@ -395,7 +403,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))); @@ -404,7 +412,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; } }); @@ -485,7 +495,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)); } @@ -512,7 +522,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Tue Mar 17 12:13:24 2015 +0100 @@ -101,7 +101,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]); } @@ -111,7 +111,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; @@ -124,7 +124,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]); } @@ -245,7 +245,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -62,7 +62,7 @@ } public LocationIdentity getLocationIdentity() { - return LocationIdentity.ANY_LOCATION; + return LocationIdentity.any(); } protected void replaceSnippetInvokes(StructuredGraph snippetGraph) { diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Tue Mar 17 12:13:24 2015 +0100 @@ -61,72 +61,144 @@ } @Test - public void constantValueProbedNullInstrument() { + public void constantValueProbedNullInstrument1() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument"); + probe.attach(instrument); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedNullInstrument2() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument"); probe.attach(instrument); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedNullInstrumentDisposed() { + public void constantValueProbedNullInstrumentDisposed1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument"); + Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument"); + probe.attach(instrument); + instrument.dispose(); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedNullInstrumentDisposed2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument"); probe.attach(instrument); instrument.dispose(); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedTwoNullInstruments() { + public void constantValueProbedTwoNullInstruments1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedThreeNullInstruments() { + public void constantValueProbedTwoNullInstruments2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + probe.attach(instrument1); + Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + probe.attach(instrument2); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedThreeNullInstruments1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3"); + probe.attach(instrument3); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedThreeNullInstruments2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + probe.attach(instrument1); + Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + probe.attach(instrument2); + Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); assertPartialEvalEquals("constant42", root); } @Test - public void constantValueProbedThreeNullInstrumentsOneDisposed() { + public void constantValueProbedThreeNullInstrumentsOneDisposed1() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe probe = result.probe(); - Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1"); + Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1"); probe.attach(instrument1); - Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2"); + Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2"); probe.attach(instrument2); - Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3"); + Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3"); + probe.attach(instrument3); + instrument2.dispose(); + assertPartialEvalEquals("constant42", root); + } + + @Test + public void constantValueProbedThreeNullInstrumentsOneDisposed2() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new ConstantTestNode(42); + RootTestNode root = new RootTestNode(fd, "constantValue", result); + root.adoptChildren(); + Probe probe = result.probe(); + Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1"); + probe.attach(instrument1); + Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2"); + probe.attach(instrument2); + Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3"); probe.attach(instrument3); instrument2.dispose(); assertPartialEvalEquals("constant42", root); @@ -167,13 +239,13 @@ Assert.assertEquals(0, count[0]); // Didn't count anything // Add a counting instrument; this changes the "Probe state" and should cause a deopt - final Instrument countingInstrument = Instrument.create(new DefaultEventListener() { + final Instrument countingInstrument = Instrument.create(new DefaultInstrumentListener() { @Override - public void enter(Node node, VirtualFrame frame) { + public void enter(Probe p) { count[0] = count[0] + 1; } - }); + }, null); probe[0].attach(countingInstrument); Assert.assertEquals(42, callTarget.call()); // Correct result diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Mar 17 12:13:24 2015 +0100 @@ -202,6 +202,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()) { @@ -219,10 +220,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) { diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Mar 17 12:13:24 2015 +0100 @@ -69,8 +69,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Tue Mar 17 12:13:24 2015 +0100 @@ -335,7 +335,7 @@ if (location.isConstant()) { LocationIdentity locationIdentity; if (location.isNullConstant()) { - locationIdentity = LocationIdentity.ANY_LOCATION; + locationIdentity = LocationIdentity.any(); } else { locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant()); } @@ -361,12 +361,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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java Tue Mar 17 12:13:24 2015 +0100 @@ -83,7 +83,7 @@ }; @Test - public void testBasicInstrumentation() { + public void testInstrumentationStructure() { // Create a simple addition AST final TruffleRuntime runtime = Truffle.getRuntime(); final TestValueNode leftValueNode = new TestValueNode(6); @@ -117,7 +117,7 @@ assertEquals(13, callTarget1.call()); // Probe the addition node - final Probe probe = addNode.probe(); + addNode.probe(); // Check the modified tree structure assertEquals(addNode, leftValueNode.getParent()); @@ -153,103 +153,129 @@ // Check that the "probed" AST still executes correctly assertEquals(13, callTarget1.call()); + } + + @Test + public void testListeners() { + + // Create a simple addition AST + final TruffleRuntime runtime = Truffle.getRuntime(); + final TestValueNode leftValueNode = new TestValueNode(6); + final TestValueNode rightValueNode = new TestValueNode(7); + final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); + final TestRootNode rootNode = new TestRootNode(addNode); + + // Creating a call target sets the parent pointers in this tree and is necessary prior to + // checking any parent/child relationships + final CallTarget callTarget = runtime.createCallTarget(rootNode); + // Probe the addition node + final Probe probe = addNode.probe(); + + // Check instrumentation with the simplest kind of counters. + // They should all be removed when the check is finished. + checkCounters(probe, callTarget, rootNode, new TestInstrumentCounter(), new TestInstrumentCounter(), new TestInstrumentCounter()); + + // Now try with the more complex flavor of listener + checkCounters(probe, callTarget, rootNode, new TestASTInstrumentCounter(), new TestASTInstrumentCounter(), new TestASTInstrumentCounter()); + + } + + private static void checkCounters(Probe probe, CallTarget callTarget, RootNode rootNode, TestCounter counterA, TestCounter counterB, TestCounter counterC) { + // Attach a counting instrument to the probe - final TestCounter counterA = new TestCounter(); counterA.attach(probe); // Attach a second counting instrument to the probe - final TestCounter counterB = new TestCounter(); counterB.attach(probe); // Run it again and check that the two instruments are working - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 1); - assertEquals(counterB.leaveCount, 1); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 1); + assertEquals(counterB.leaveCount(), 1); - // Remove counterA and check the "instrument chain" + // Remove counterA counterA.dispose(); - iterator = probeNode.getChildren().iterator(); // Run it again and check that instrument B is still working but not A - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 2); - assertEquals(counterB.leaveCount, 2); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 2); + assertEquals(counterB.leaveCount(), 2); // Simulate a split by cloning the AST - final CallTarget callTarget2 = runtime.createCallTarget((TestRootNode) rootNode.copy()); + final CallTarget callTarget2 = Truffle.getRuntime().createCallTarget((TestRootNode) rootNode.copy()); // Run the clone and check that instrument B is still working but not A assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 3); - assertEquals(counterB.leaveCount, 3); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 3); + assertEquals(counterB.leaveCount(), 3); // Run the original and check that instrument B is still working but not A assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 4); - assertEquals(counterB.leaveCount, 4); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 4); + assertEquals(counterB.leaveCount(), 4); // Attach a second instrument to the probe - final TestCounter counterC = new TestCounter(); counterC.attach(probe); // Run the original and check that instruments B,C working but not A - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 5); - assertEquals(counterB.leaveCount, 5); - assertEquals(counterC.enterCount, 1); - assertEquals(counterC.leaveCount, 1); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 5); + assertEquals(counterB.leaveCount(), 5); + assertEquals(counterC.enterCount(), 1); + assertEquals(counterC.leaveCount(), 1); // Run the clone and check that instruments B,C working but not A assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 6); - assertEquals(counterB.leaveCount, 6); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 6); + assertEquals(counterB.leaveCount(), 6); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); // Remove instrumentC counterC.dispose(); // Run the original and check that instrument B working but not A,C - assertEquals(13, callTarget1.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 7); - assertEquals(counterB.leaveCount, 7); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(13, callTarget.call()); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 7); + assertEquals(counterB.leaveCount(), 7); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); // Run the clone and check that instrument B working but not A,C assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 8); - assertEquals(counterB.leaveCount, 8); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 8); + assertEquals(counterB.leaveCount(), 8); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); // Remove instrumentB counterB.dispose(); // Run both the original and clone, check that no instruments working - assertEquals(13, callTarget1.call()); + assertEquals(13, callTarget.call()); assertEquals(13, callTarget2.call()); - assertEquals(counterA.enterCount, 1); - assertEquals(counterA.leaveCount, 1); - assertEquals(counterB.enterCount, 8); - assertEquals(counterB.leaveCount, 8); - assertEquals(counterC.enterCount, 2); - assertEquals(counterC.leaveCount, 2); + assertEquals(counterA.enterCount(), 1); + assertEquals(counterA.leaveCount(), 1); + assertEquals(counterB.enterCount(), 8); + assertEquals(counterB.leaveCount(), 8); + assertEquals(counterC.enterCount(), 2); + assertEquals(counterC.leaveCount(), 2); + } @Test @@ -313,131 +339,6 @@ } - @Test - public void testProbeLite() { - - // Use the "lite-probing" option, limited to a single pass of - // probing and a single Instrument at each probed node. This - // particular test uses a shared event listener at every - // lite-probed node. - final TestEventListener listener = new TestEventListener(); - - TestASTLiteProber astLiteProber = new TestASTLiteProber(listener); - Probe.registerASTProber(astLiteProber); - - // Create a simple addition AST - final TruffleRuntime runtime = Truffle.getRuntime(); - final TestValueNode leftValueNode = new TestValueNode(6); - final TestValueNode rightValueNode = new TestValueNode(7); - final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); - final TestRootNode rootNode = new TestRootNode(addNode); - - // Creating a call target sets the parent pointers in this tree and is necessary prior to - // checking any parent/child relationships - final CallTarget callTarget = runtime.createCallTarget(rootNode); - - // Check that the instrument is working as expected. - assertEquals(0, listener.counter); - callTarget.call(); - assertEquals(2, listener.counter); - - // Check that you can't probe a node that's already received a probeLite() call - try { - leftValueNode.probe(); - fail(); - } catch (IllegalStateException e) { - } - - try { - rightValueNode.probe(); - fail(); - } catch (IllegalStateException e) { - } - - // Check tree structure - assertTrue(leftValueNode.getParent() instanceof TestLanguageWrapperNode); - assertTrue(rightValueNode.getParent() instanceof TestLanguageWrapperNode); - TestLanguageWrapperNode leftWrapper = (TestLanguageWrapperNode) leftValueNode.getParent(); - TestLanguageWrapperNode rightWrapper = (TestLanguageWrapperNode) rightValueNode.getParent(); - assertEquals(addNode, leftWrapper.getParent()); - assertEquals(addNode, rightWrapper.getParent()); - Iterator iterator = addNode.getChildren().iterator(); - assertEquals(leftWrapper, iterator.next()); - assertEquals(rightWrapper, iterator.next()); - assertFalse(iterator.hasNext()); - assertEquals(rootNode, addNode.getParent()); - iterator = rootNode.getChildren().iterator(); - assertEquals(addNode, iterator.next()); - assertFalse(iterator.hasNext()); - - // Check that you can't get a probe on the wrappers because they were "lite-probed" - try { - leftWrapper.getProbe(); - fail(); - } catch (IllegalStateException e) { - } - try { - rightWrapper.getProbe(); - fail(); - } catch (IllegalStateException e) { - } - - // Check that you can't probe the wrappers - try { - leftWrapper.probe(); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - try { - rightWrapper.probe(); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - try { - leftWrapper.probeLite(null); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - try { - rightWrapper.probeLite(null); - fail(); - } catch (ProbeException e) { - assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE); - } - - // Use reflection to check that each WrapperNode has a ProbeLiteNode with a - // SimpleEventListener - try { - java.lang.reflect.Field probeNodeField = leftWrapper.getClass().getDeclaredField("probeNode"); - - // cheat: probeNode is private, so we change it's accessibility at runtime - probeNodeField.setAccessible(true); - ProbeNode probeNode = (ProbeNode) probeNodeField.get(leftWrapper); - - // hack: Since ProbeLiteNode is not visible, we do a string compare here - assertTrue(probeNode.getClass().toString().endsWith("ProbeLiteNode")); - - // Now we do the same to check the type of the eventListener in ProbeLiteNode - java.lang.reflect.Field eventListenerField = probeNode.getClass().getDeclaredField("eventListener"); - eventListenerField.setAccessible(true); - TruffleEventListener eventListener = (TruffleEventListener) eventListenerField.get(probeNode); - assertTrue(eventListener instanceof SimpleEventListener); - - // Reset accessibility - probeNodeField.setAccessible(false); - eventListenerField.setAccessible(false); - - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - fail(); - } - - Probe.unregisterASTProber(astLiteProber); - - } - private abstract class TestLanguageNode extends Node { public abstract Object execute(VirtualFrame vFrame); @@ -479,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 @@ -578,28 +475,51 @@ } } + private interface TestCounter { + + int enterCount(); + + int leaveCount(); + + void attach(Probe probe); + + void dispose(); + + } + /** - * A counter for the number of times execution enters and leaves a probed AST node. + * A counter for the number of times execution enters and leaves a probed AST node, using the + * simplest kind of listener. */ - private class TestCounter { + private class TestInstrumentCounter implements TestCounter { public int enterCount = 0; public int leaveCount = 0; public final Instrument instrument; - public TestCounter() { - instrument = Instrument.create(new SimpleEventListener() { + public TestInstrumentCounter() { + this.instrument = Instrument.create(new SimpleInstrumentListener() { @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe probe) { enterCount++; } @Override - public void returnAny(Node node, VirtualFrame vFrame) { + public void returnAny(Probe probe) { leaveCount++; } + }, "Instrumentation Test Counter"); + + } + + public int enterCount() { + return enterCount; + } + + public int leaveCount() { + return leaveCount; } public void attach(Probe probe) { @@ -609,7 +529,50 @@ public void dispose() { instrument.dispose(); } + } + /** + * A counter for the number of times execution enters and leaves a probed AST node, using the + * simplest kind of listener. + */ + private class TestASTInstrumentCounter implements TestCounter { + + public int enterCount = 0; + public int leaveCount = 0; + public final Instrument instrument; + + public TestASTInstrumentCounter() { + this.instrument = Instrument.create(new SimpleASTInstrumentListener() { + + @Override + public void enter(Probe probe, Node node, VirtualFrame vFrame) { + enterCount++; + } + + @Override + public void returnAny(Probe probe, Node node, VirtualFrame vFrame) { + leaveCount++; + } + + }, "Instrumentation Test Counter"); + + } + + public int enterCount() { + return enterCount; + } + + public int leaveCount() { + return leaveCount; + } + + public void attach(Probe probe) { + probe.attach(instrument); + } + + public void dispose() { + instrument.dispose(); + } } /** @@ -641,38 +604,28 @@ } /** - * "lite-probes" every value node with a shared event listener. + * Counts the number of "enter" events at probed nodes using the simplest AST listener. */ - private static final class TestASTLiteProber implements NodeVisitor, ASTProber { - private final TruffleEventListener eventListener; - - public TestASTLiteProber(SimpleEventListener simpleEventListener) { - this.eventListener = simpleEventListener; - } - - public boolean visit(Node node) { - if (node instanceof TestValueNode) { - final TestLanguageNode testNode = (TestValueNode) node; - testNode.probeLite(eventListener); - } - return true; - } - - public void probeAST(Node node) { - node.accept(this); - } - } - - /** - * Counts the number of "enter" events at probed nodes. - * - */ - static final class TestEventListener extends SimpleEventListener { + static final class TestInstrumentListener extends DefaultInstrumentListener { public int counter = 0; @Override - public void enter(Node node, VirtualFrame frame) { + public void enter(Probe probe) { + counter++; + } + + } + + /** + * Counts the number of "enter" events at probed nodes using the AST listener. + */ + static final class TestASTInstrumentListener extends DefaultASTInstrumentListener { + + public int counter = 0; + + @Override + public void enter(Probe probe, Node node, VirtualFrame vFrame) { counter++; } @@ -692,10 +645,10 @@ // where we want to count executions. // it will get copied when ASTs cloned, so // keep the count in this outer class. - probe.attach(Instrument.create(new SimpleEventListener() { + probe.attach(Instrument.create(new DefaultInstrumentListener() { @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe p) { count++; } }, "Instrumentation Test MultiCounter")); diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/tools/TestNodes.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTInstrumentListener.java Tue Mar 17 12:13:24 2015 +0100 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * A listener of Truffle AST runtime execution events that can collect information, examine the + * execution state at a particular node, and possibly intervene on behalf of an external tool. + */ +public interface ASTInstrumentListener { + + /** + * Receive notification that an AST node's execute method is about to be called. + */ + void enter(Probe probe, Node node, VirtualFrame vFrame); + + /** + * Receive notification that an AST Node's {@code void}-valued execute method has just returned. + */ + void returnVoid(Probe probe, Node node, VirtualFrame vFrame); + + /** + * Receive notification that an AST Node's execute method has just returned a value (boxed if + * primitive). + */ + void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result); + + /** + * Receive notification that an AST Node's execute method has just thrown an exception. + */ + void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception); + +} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue Mar 17 12:13:24 2015 +0100 @@ -27,45 +27,71 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; import com.oracle.truffle.api.instrument.impl.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.*; // TODO (mlvdv) migrate some of this to external documentation. // TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe), // then break out some of the nested classes into package privates. /** * A dynamically added/removed binding between a {@link Probe}, which provides notification of - * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest - * Language (GL) Truffle AST, and a {@linkplain TruffleEventListener listener}, which consumes - * notifications on behalf of an external tool. + * execution events taking place at a {@link Node} in a Guest Language (GL) Truffle AST, + * and a listener, which consumes notifications on behalf of an external tool. There are at + * present two kinds of listeners that be used: + *
    + *
  1. {@link InstrumentListener} is the simplest and is intended for tools that require no access + * to the internal execution state of the Truffle execution, only that execution has passed + * through a particular location in the program. Information about that location is made available + * via the {@link Probe} argument in notification methods, including the {@linkplain SourceSection + * source location} of the node and any {@linkplain SyntaxTag tags} that have been applied to the + * node.
  2. + *
  3. {@link ASTInstrumentListener} reports the same events and {@link Probe} argument, but + * additionally provides access to the execution state via the explicit {@link Node} and + * {@link Frame} at the current execution site.
  4. + *
*

*

Summary: How to "instrument" an AST location:

+ *

*

    - *
  1. Create an implementation of {@link TruffleEventListener} that responds to events on behalf of - * a tool.
  2. - *
  3. Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.
  4. + *
  5. Create an implementation of a listener interface.
  6. + *
  7. Create an Instrument via factory methods + * {@link Instrument#create(InstrumentListener, String)} or + * {@link Instrument#create(ASTInstrumentListener, String)}.
  8. *
  9. "Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event * notifications begin to arrive at the listener.
  10. - *
  11. When no longer needed, "detach" the Instrument via {@link TruffleEventInstrument#dispose()}, - * at which point event notifications to the listener cease, and the Instrument becomes unusable.
  12. + *
  13. When no longer needed, "detach" the Instrument via {@link ASTInstrument#dispose()}, at which + * point event notifications to the listener cease, and the Instrument becomes unusable.
  14. *
*

*

Options for creating listeners:

*

*

    - *
  1. Implement the interface {@link TruffleEventListener}. The event handling methods account for - * both the entry into an AST node (about to call) and several possible kinds of exit from an AST - * node (just returned).
  2. - *
  3. Extend {@link DefaultEventListener}, which provides a no-op implementation of every - * {@link TruffleEventListener} method; override the methods of interest.
  4. - *
  5. Extend {@link SimpleEventListener}, where return values are ignored so only two methods (for - * "enter" and "return") will notify all events.
  6. + *
  7. Implement one of the listener interfaces: {@link InstrumentListener} or + * {@link ASTInstrumentListener} . Their event handling methods account for both the entry into an + * AST node (about to call) and three possible kinds of execution return from an AST node.
  8. + *
  9. Extend one of the helper implementations: {@link DefaultInstrumentListener} or + * {@link DefaultASTInstrumentListener}. These provide no-op implementation of every listener + * method, so only the methods of interest need to be overridden.
  10. + *
  11. Extend one of the helper implementations: {@link SimpleInstrumentListener} or + * {@link SimpleASTInstrumentListener}. These re-route all execution returns to a single + * method, ignoring return values, so only two methods (for "enter" and "return") will notify all + * events.
  12. *
*

- *

General guidelines for listener implementation:

+ *

General guidelines for {@link ASTInstrumentListener} implementation:

*

- * When an Instrument is attached to a Probe, the listener effectively becomes part of the executing - * GL program; performance can be affected by the listener's implementation. + * Unlike the listener interface {@link InstrumentListener}, which isolates implementations + * completely from Truffle internals (and is thus Truffle-safe), implementations of + * {@link ASTInstrumentListener} can interact directly with (and potentially affect) Truffle + * execution in general and Truffle optimization in particular. For example, it is possible to + * implement a debugger with this interface. + *

+ *

+ * As a consequence, implementations of {@link ASTInstrumentListener} effectively become part of the + * Truffle execution and must be coded according to general guidelines for Truffle implementations. + * For example: *

    *
  • Do not store {@link Frame} or {@link Node} references in fields.
  • *
  • Prefer {@code final} fields and (where performance is important) short methods.
  • @@ -78,16 +104,18 @@ * should be minimal. *
  • On the other hand, implementations should prevent Truffle from inlining beyond a reasonable * point with the method annotation {@link TruffleBoundary}.
  • - *
  • The implicit "outer" pointer in a non-static inner class is a useful way to implement - * callbacks to owner tools.
  • - *
  • Primitive-valued return events are boxed for notification, but Truffle will eliminate the - * boxing if they are cast back to their primitive values quickly (in particular before crossing any - * {@link TruffleBoundary} annotations). + *
  • The implicit "outer" pointer in a non-static inner class is a useful (and + * Truffle-optimizable) way to implement callbacks to owner tools.
  • + *
  • Primitive-valued return events are boxed for event notification, but Truffle will eliminate + * the boxing if they are cast back to their primitive values quickly (in particular before crossing + * any {@link TruffleBoundary} annotations). *
*

*

Allowing for AST cloning:

*

- * Truffle routinely clones ASTs, which has consequences for listener implementation. + * Truffle routinely clones ASTs, which has consequences for implementations of + * {@link ASTInstrumentListener} (but not for implementations of {@link InstrumentListener}, from + * which cloning is hidden). *

    *
  • Even though a {@link Probe} is uniquely associated with a particular location in the * executing Guest Language program, execution events at that location will in general be @@ -98,22 +126,18 @@ * be treated as equivalent for most purposes.
  • *
*

- *

Access to execution state:

+ *

Access to execution state via {@link ASTInstrumentListener}:

*

*

    - *
  • Event notification arguments provide primary access to the GL program's execution states: + *
  • Notification arguments provide primary access to the GL program's execution states: *
      *
    • {@link Node}: the concrete node (in one of the AST's clones) from which the event originated. *
    • *
    • {@link VirtualFrame}: the current execution frame. *
    - *
  • Some global information is available, for example the execution + *
  • Truffle global information is available, for example the execution * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.
  • - *
  • Additional information needed by a listener could be stored when created, preferably - * {@code final} of course. For example, a reference to the {@link Probe} to which the listener's - * Instrument has been attached would give access to its corresponding - * {@linkplain Probe#getProbedSourceSection() source location} or to the collection of - * {@linkplain SyntaxTag tags} currently applied to the Probe.
  • + *
  • Additional API access to execution state may be added in the future.
  • *
*

*

Activating and deactivating Instruments:

@@ -125,8 +149,8 @@ * error to attempt attaching a previously attached instrument. *
  • Attaching an instrument modifies every existing clone of the AST to which it is being * attached, which can trigger deoptimization.
  • - *
  • The method {@link TruffleEventInstrument#dispose()} makes an instrument inactive by removing - * it from the Probe to which it was attached and rendering it permanently inert.
  • + *
  • The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the + * Probe to which it was attached and rendering it permanently inert.
  • *
  • Disposal removes the implementation of an instrument from all ASTs to which it was attached, * which can trigger deoptimization.
  • * @@ -142,26 +166,32 @@ * Disclaimer: experimental; under development. * * @see Probe - * @see TruffleEventListener + * @see TruffleEvents */ public abstract class Instrument { /** * Creates an instrument that will route execution events to a listener. * - * @param listener a listener for event generated by the instrument - * @param instrumentInfo optional description of the instrument's role + * @param listener a minimal listener for event generated by the instrument. + * @param instrumentInfo optional description of the instrument's role, useful for debugging. * @return a new instrument, ready for attachment at a probe */ - public static Instrument create(TruffleEventListener listener, String instrumentInfo) { - return new TruffleEventInstrument(listener, instrumentInfo); + public static Instrument create(InstrumentListener listener, String instrumentInfo) { + return new BasicInstrument(listener, instrumentInfo); } /** - * Creates an instrument that will route execution events to a listener. + * Creates an instrument that will route execution events to a listener, along with access to + * internal execution state. + * + * @param astListener a listener for event generated by the instrument that provides access to + * internal execution state + * @param instrumentInfo optional description of the instrument's role, useful for debugging. + * @return a new instrument, ready for attachment at a probe */ - public static Instrument create(TruffleEventListener listener) { - return new TruffleEventInstrument(listener, null); + public static Instrument create(ASTInstrumentListener astListener, String instrumentInfo) { + return new ASTInstrument(astListener, instrumentInfo); } // TODO (mlvdv) experimental @@ -177,7 +207,7 @@ */ private boolean isDisposed = false; - private Probe probe = null; + protected Probe probe = null; /** * Optional documentation, mainly for debugging. @@ -220,32 +250,30 @@ return isDisposed; } - abstract InstrumentNode addToChain(InstrumentNode nextNode); + abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode); /** - * Removes this instrument from an instrument chain. + * An instrument that propagates events to an instance of {@link InstrumentListener}. */ - abstract InstrumentNode removeFromChain(InstrumentNode instrumentNode); - - private static final class TruffleEventInstrument extends Instrument { + private static final class BasicInstrument extends Instrument { /** * Tool-supplied listener for events. */ - private final TruffleEventListener toolEventListener; + private final InstrumentListener instrumentListener; - private TruffleEventInstrument(TruffleEventListener listener, String instrumentInfo) { + private BasicInstrument(InstrumentListener basicListener, String instrumentInfo) { super(instrumentInfo); - this.toolEventListener = listener; + this.instrumentListener = basicListener; } @Override - InstrumentNode addToChain(InstrumentNode nextNode) { - return new TruffleEventInstrumentNode(nextNode); + AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { + return new BasicInstrumentNode(nextNode); } @Override - InstrumentNode removeFromChain(InstrumentNode instrumentNode) { + AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { boolean found = false; if (instrumentNode != null) { if (instrumentNode.getInstrument() == this) { @@ -253,7 +281,7 @@ return instrumentNode.nextInstrument; } // Match not at the head of the chain; remove it. - found = instrumentNode.removeFromChain(TruffleEventInstrument.this); + found = instrumentNode.removeFromChain(BasicInstrument.this); } if (!found) { throw new IllegalStateException("Couldn't find instrument node to remove: " + this); @@ -262,35 +290,35 @@ } @NodeInfo(cost = NodeCost.NONE) - private final class TruffleEventInstrumentNode extends InstrumentNode { + private final class BasicInstrumentNode extends AbstractInstrumentNode { - private TruffleEventInstrumentNode(InstrumentNode nextNode) { + private BasicInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); } public void enter(Node node, VirtualFrame vFrame) { - TruffleEventInstrument.this.toolEventListener.enter(node, vFrame); + BasicInstrument.this.instrumentListener.enter(BasicInstrument.this.probe); if (nextInstrument != null) { nextInstrument.enter(node, vFrame); } } public void returnVoid(Node node, VirtualFrame vFrame) { - TruffleEventInstrument.this.toolEventListener.returnVoid(node, vFrame); + BasicInstrument.this.instrumentListener.returnVoid(BasicInstrument.this.probe); if (nextInstrument != null) { nextInstrument.returnVoid(node, vFrame); } } public void returnValue(Node node, VirtualFrame vFrame, Object result) { - TruffleEventInstrument.this.toolEventListener.returnValue(node, vFrame, result); + BasicInstrument.this.instrumentListener.returnValue(BasicInstrument.this.probe, result); if (nextInstrument != null) { nextInstrument.returnValue(node, vFrame, result); } } public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - TruffleEventInstrument.this.toolEventListener.returnExceptional(node, vFrame, exception); + BasicInstrument.this.instrumentListener.returnExceptional(BasicInstrument.this.probe, exception); if (nextInstrument != null) { nextInstrument.returnExceptional(node, vFrame, exception); } @@ -298,7 +326,91 @@ public String instrumentationInfo() { final String info = getInstrumentInfo(); - return info != null ? info : toolEventListener.getClass().getSimpleName(); + return info != null ? info : instrumentListener.getClass().getSimpleName(); + } + } + } + + /** + * Removes this instrument from an instrument chain. + */ + abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode); + + /** + * An instrument that propagates events to an instance of {@link ASTInstrumentListener}. + */ + private static final class ASTInstrument extends Instrument { + + /** + * Tool-supplied listener for AST events. + */ + private final ASTInstrumentListener astListener; + + private ASTInstrument(ASTInstrumentListener astListener, String instrumentInfo) { + super(instrumentInfo); + this.astListener = astListener; + } + + @Override + AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { + return new ASTInstrumentNode(nextNode); + } + + @Override + AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { + boolean found = false; + if (instrumentNode != null) { + if (instrumentNode.getInstrument() == this) { + // Found the match at the head of the chain + return instrumentNode.nextInstrument; + } + // Match not at the head of the chain; remove it. + found = instrumentNode.removeFromChain(ASTInstrument.this); + } + if (!found) { + throw new IllegalStateException("Couldn't find instrument node to remove: " + this); + } + return instrumentNode; + } + + @NodeInfo(cost = NodeCost.NONE) + private final class ASTInstrumentNode extends AbstractInstrumentNode { + + private ASTInstrumentNode(AbstractInstrumentNode nextNode) { + super(nextNode); + } + + public void enter(Node node, VirtualFrame vFrame) { + ASTInstrument.this.astListener.enter(ASTInstrument.this.probe, node, vFrame); + if (nextInstrument != null) { + nextInstrument.enter(node, vFrame); + } + } + + public void returnVoid(Node node, VirtualFrame vFrame) { + ASTInstrument.this.astListener.returnVoid(ASTInstrument.this.probe, node, vFrame); + if (nextInstrument != null) { + nextInstrument.returnVoid(node, vFrame); + } + } + + public void returnValue(Node node, VirtualFrame vFrame, Object result) { + ASTInstrument.this.astListener.returnValue(ASTInstrument.this.probe, node, vFrame, result); + if (nextInstrument != null) { + nextInstrument.returnValue(node, vFrame, result); + } + } + + public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { + ASTInstrument.this.astListener.returnExceptional(ASTInstrument.this.probe, node, vFrame, exception); + if (nextInstrument != null) { + nextInstrument.returnExceptional(node, vFrame, exception); + } + } + + public String instrumentationInfo() { + final String info = getInstrumentInfo(); + return info != null ? info : astListener.getClass().getSimpleName(); } } @@ -318,12 +430,12 @@ } @Override - InstrumentNode addToChain(InstrumentNode nextNode) { + AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { return new TruffleOptInstrumentNode(nextNode); } @Override - InstrumentNode removeFromChain(InstrumentNode instrumentNode) { + AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) { boolean found = false; if (instrumentNode != null) { if (instrumentNode.getInstrument() == this) { @@ -340,11 +452,11 @@ } @NodeInfo(cost = NodeCost.NONE) - private final class TruffleOptInstrumentNode extends InstrumentNode { + private final class TruffleOptInstrumentNode extends AbstractInstrumentNode { private boolean isCompiled; - private TruffleOptInstrumentNode(InstrumentNode nextNode) { + private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); this.isCompiled = CompilerDirectives.inCompiledCode(); } @@ -386,10 +498,11 @@ } @NodeInfo(cost = NodeCost.NONE) - abstract class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode { - @Child protected InstrumentNode nextInstrument; + abstract class AbstractInstrumentNode extends Node implements TruffleEvents, InstrumentationNode { - protected InstrumentNode(InstrumentNode nextNode) { + @Child protected AbstractInstrumentNode nextInstrument; + + protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) { this.nextInstrument = nextNode; } diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentListener.java Tue Mar 17 12:13:24 2015 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument; + +/** + * A listener of Truffle execution events that can collect information on behalf of an external + * tool. Contextual information about the source of the event, if not stored in the implementation + * of the listener, can be obtained via access to the {@link Probe} that generates the event. + */ +public interface InstrumentListener { + + /** + * Receive notification that an AST node's execute method is about to be called. + */ + void enter(Probe probe); + + /** + * Receive notification that an AST Node's {@code void}-valued execute method has just returned. + */ + void returnVoid(Probe probe); + + /** + * Receive notification that an AST Node's execute method has just returned a value (boxed if + * primitive). + */ + void returnValue(Probe probe, Object result); + + /** + * Receive notification that an AST Node's execute method has just thrown an exception. + */ + void returnExceptional(Probe probe, Exception exception); +} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 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 @@ -24,6 +24,7 @@ */ package com.oracle.truffle.api.instrument; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; /** @@ -36,4 +37,31 @@ * A short description of the particular role played by the node, intended to support debugging. */ String instrumentationInfo(); + + /** + * Events at a Truffle node that get propagated through the Instrumentation Framework. + */ + interface TruffleEvents { + + /** + * An AST node's execute method is about to be called. + */ + void enter(Node node, VirtualFrame vFrame); + + /** + * An AST Node's {@code void}-valued execute method has just returned. + */ + void returnVoid(Node node, VirtualFrame vFrame); + + /** + * An AST Node's execute method has just returned a value (boxed if primitive). + */ + void returnValue(Node node, VirtualFrame vFrame, Object result); + + /** + * An AST Node's execute method has just thrown an exception. + */ + void returnExceptional(Node node, VirtualFrame vFrame, Exception exception); + + } } diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Tue Mar 17 12:13:24 2015 +0100 @@ -29,6 +29,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.api.utilities.*; @@ -41,9 +42,9 @@ * is intended to persist at the location, even if the specific node instance is * {@linkplain Node#replace(Node) replaced}. *

    - * The effect of a binding is to intercept {@linkplain TruffleEventListener execution events} - * arriving at the node and notify each attached {@link Instrument} before execution is allowed to - * proceed to the child. + * The effect of a binding is to intercept {@linkplain TruffleEvents execution events} arriving at + * the node and notify each attached {@link Instrument} before execution is allowed to proceed to + * the child. *

    * A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one Probe * can be inserted at a node. diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeFailure.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Tue Mar 17 12:13:24 2015 +0100 @@ -27,14 +27,26 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.Instrument.InstrumentNode; +import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode; +import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents; import com.oracle.truffle.api.nodes.*; 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 TruffleEventListener, 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 @@ -84,14 +96,13 @@ /** * Gets the node being "wrapped", i.e. the AST node for which - * {@linkplain TruffleEventListener execution events} will be reported through the - * Instrumentation Framework. + * {@linkplain InstrumentationNode.TruffleEvents execution events} will be reported through + * the Instrumentation Framework. */ Node getChild(); /** - * Gets the {@link Probe} responsible for installing this wrapper; none if the wrapper - * installed via {@linkplain Node#probeLite(TruffleEventListener) "lite-Probing"}. + * Gets the {@link Probe} responsible for installing this wrapper. */ Probe getProbe(); @@ -99,7 +110,6 @@ * Implementation support for completing a newly created wrapper node. */ void insertProbe(ProbeNode probeNode); - } /** @@ -108,201 +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, TruffleEventListener eventListener) { - final ProbeLiteNode probeLiteNode = new ProbeLiteNode(eventListener); - 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 InstrumentNode} to this chain. - * - * @throws IllegalStateException if at a "lite-Probed" location. + * Adds an {@link AbstractInstrumentNode} to this chain. */ - 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 InstrumentNode} node in chain; {@code null} of no instruments in chain. - */ - @Child protected InstrumentNode 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 InstrumentNode 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 TruffleEventListener} passed in during construction. - */ - @NodeInfo(cost = NodeCost.NONE) - private static final class ProbeLiteNode extends ProbeNode { - - private final TruffleEventListener eventListener; - - private ProbeLiteNode(TruffleEventListener eventListener) { - this.eventListener = 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) { - eventListener.enter(node, vFrame); - } - - public void returnVoid(Node node, VirtualFrame vFrame) { - eventListener.returnVoid(node, vFrame); - } - - public void returnValue(Node node, VirtualFrame vFrame, Object result) { - eventListener.returnValue(node, vFrame, result); - } - - public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - eventListener.returnExceptional(node, vFrame, exception); - } - - public String instrumentationInfo() { - return "\"Lite\" probe"; - } - - } } diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java Tue Mar 17 12:05:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * A listener of Truffle AST runtime execution events that can collect information and possibly - * intervene on behalf of an external tool. - */ -public interface TruffleEventListener { - - /** - * Receive notification that an AST node's execute method is about to be called. - */ - void enter(Node node, VirtualFrame vFrame); - - /** - * Receive notification that an AST Node's {@code void}-valued execute method has just returned. - */ - void returnVoid(Node node, VirtualFrame vFrame); - - /** - * Receive notification that an AST Node'sexecute method has just returned a value (boxed if - * primitive). - */ - void returnValue(Node node, VirtualFrame vFrame, Object result); - - /** - * Receive notification that an AST Node's execute method has just thrown an exception. - */ - void returnExceptional(Node node, VirtualFrame vFrame, Exception exception); - -} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTInstrumentListener.java Tue Mar 17 12:13:24 2015 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument.impl; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; + +/** + * A listener for AST {@linkplain ASTInstrumentListener execution events} that provides a no-op + * implementation of every event. + */ +public class DefaultASTInstrumentListener implements ASTInstrumentListener { + + public void enter(Probe probe, Node node, VirtualFrame vFrame) { + } + + public void returnVoid(Probe probe, Node node, VirtualFrame vFrame) { + } + + public void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { + } + + public void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) { + } + +} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java Tue Mar 17 12:05:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument.impl; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * A listener for AST {@linkplain TruffleEventListener execution events} that provides a no-op - * implementation of every event. - */ -public class DefaultEventListener implements TruffleEventListener { - - public void enter(Node node, VirtualFrame vFrame) { - } - - public void returnVoid(Node node, VirtualFrame vFrame) { - } - - public void returnValue(Node node, VirtualFrame vFrame, Object result) { - } - - public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) { - } - -} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrumentListener.java Tue Mar 17 12:13:24 2015 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument.impl; + +import com.oracle.truffle.api.instrument.*; + +/** + * A listener for Truffle execution events that provides a no-op implementation of every event. + */ +public class DefaultInstrumentListener implements InstrumentListener { + + public void enter(Probe probe) { + } + + public void returnVoid(Probe probe) { + } + + public void returnValue(Probe probe, Object result) { + } + + public void returnExceptional(Probe probe, Exception exception) { + } +} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleASTInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleASTInstrumentListener.java Tue Mar 17 12:13:24 2015 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument.impl; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; + +/** + * An abstract listener for AST {@linkplain ASTInstrumentListener execution events} that ignores + * return values and supports handling all events by overriding only two methods: + *

      + *
    • {@link #enter(Probe, Node, VirtualFrame)}, and
    • + *
    • {@link #returnAny(Probe, Node, VirtualFrame)}.
    • + *
    + */ +public abstract class SimpleASTInstrumentListener implements ASTInstrumentListener { + + public void enter(Probe probe, Node node, VirtualFrame vFrame) { + } + + /** + * Receive notification that one of an AST Node's execute methods has just returned by any + * means: with or without a return value (ignored) or via exception (ignored). + * + * @param probe where the event originated + * @param node specific node of the event + * @param vFrame + */ + protected void returnAny(Probe probe, Node node, VirtualFrame vFrame) { + } + + public final void returnVoid(Probe probe, Node node, VirtualFrame vFrame) { + returnAny(probe, node, vFrame); + } + + public final void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) { + returnAny(probe, node, vFrame); + } + + public final void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception e) { + returnAny(probe, node, vFrame); + } + +} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java Tue Mar 17 12:05:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument.impl; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * An abstract listener for AST {@linkplain TruffleEventListener execution events} that ignores - * return values and supports handling all events by overriding only two methods: - *
      - *
    • {@link #enter(Node, VirtualFrame)}, and
    • - *
    • {@link #returnAny(Node, VirtualFrame)}.
    • - *
    - */ -public abstract class SimpleEventListener implements TruffleEventListener { - - public void enter(Node node, VirtualFrame vFrame) { - } - - /** - * Receive notification that one of an AST Node's execute methods has just returned by any - * means: with or without a return value (ignored) or via exception (ignored). - * - * @param node - * @param vFrame - */ - public void returnAny(Node node, VirtualFrame vFrame) { - } - - public final void returnVoid(Node node, VirtualFrame vFrame) { - returnAny(node, vFrame); - } - - public final void returnValue(Node node, VirtualFrame vFrame, Object result) { - returnAny(node, vFrame); - } - - public final void returnExceptional(Node node, VirtualFrame vFrame, Exception e) { - returnAny(node, vFrame); - } - -} diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleInstrumentListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleInstrumentListener.java Tue Mar 17 12:13:24 2015 +0100 @@ -0,0 +1,63 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument.impl; + +import com.oracle.truffle.api.instrument.*; + +/** + * An abstract listener for Truffle {@linkplain InstrumentListener execution events} that ignores + * return values and supports handling all events by overriding only two methods: + *
      + *
    • {@link #enter(Probe)}, and
    • + *
    • {@link #returnAny(Probe)}.
    • + *
    + */ +public abstract class SimpleInstrumentListener implements InstrumentListener { + + public void enter(Probe probe) { + } + + /** + * Receive notification that an execute method has just returned by any means: with or without a + * return value (ignored) or via exception (ignored). + * + * @param probe + */ + protected void returnAny(Probe probe) { + } + + public final void returnVoid(Probe probe) { + returnAny(probe); + } + + public final void returnValue(Probe probe, Object result) { + returnAny(probe); + } + + public final void returnExceptional(Probe probe, Exception e) { + returnAny(probe); + } + +} diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue Mar 17 12:13:24 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(TruffleEventListener)} 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 eventListener - * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged - */ - public final void probeLite(TruffleEventListener eventListener) { - - 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, eventListener); - - // 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 b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java Tue Mar 17 12:13:24 2015 +0100 @@ -28,7 +28,6 @@ import java.util.*; import java.util.Map.Entry; -import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.instrument.impl.*; import com.oracle.truffle.api.nodes.*; @@ -49,7 +48,7 @@ *

    *

      *
    • "Execution call" on a node is is defined as invocation of a node method that is instrumented - * to produce the event {@link TruffleEventListener#enter(Node, VirtualFrame)};
    • + * to produce the event {@link InstrumentListener#enter(Probe)}; *
    • Execution calls are tabulated only at instrumented nodes, i.e. those for which * {@linkplain Node#isInstrumentable() isInstrumentable() == true};
    • *
    • Execution calls are tabulated only at nodes present in the AST when originally created; @@ -227,7 +226,7 @@ * A listener for events at each instrumented AST location. This listener counts * "execution calls" to the instrumented node. */ - private final class CoverageRecord extends DefaultEventListener { + private final class CoverageRecord extends DefaultInstrumentListener { private final SourceSection srcSection; // The text of the code being counted private Instrument instrument; // The attached Instrument, in case need to remove. @@ -238,7 +237,7 @@ } @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe probe) { if (isEnabled()) { count++; } diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java Tue Mar 17 12:13:24 2015 +0100 @@ -49,7 +49,7 @@ *

      *

        *
      • "Execution call" on a node is is defined as invocation of a node method that is instrumented - * to produce the event {@link TruffleEventListener#enter(Node, VirtualFrame)};
      • + * to produce the event {@link ASTInstrumentListener#enter(Probe, Node, VirtualFrame)}; *
      • Execution calls are tabulated only at instrumented nodes, i.e. those for which * {@linkplain Node#isInstrumentable() isInstrumentable() == true};
      • *
      • Execution calls are tabulated only at nodes present in the AST when originally created; @@ -95,15 +95,15 @@ * Listener for events at instrumented nodes. Counts are maintained in a shared table, so the * listener is stateless and can be shared by every {@link Instrument}. */ - private final TruffleEventListener eventListener = new DefaultEventListener() { + private final ASTInstrumentListener instrumentListener = new DefaultASTInstrumentListener() { @Override - public void enter(Node node, VirtualFrame vFrame) { + public void enter(Probe probe, Node node, VirtualFrame vFrame) { if (isEnabled()) { final Class nodeClass = node.getClass(); /* * Everything up to here is inlined by Truffle compilation. Delegate the next part * to a method behind an inlining boundary. - * + * * Note that it is not permitted to pass a {@link VirtualFrame} across an inlining * boundary; they are truly virtual in inlined code. */ @@ -280,7 +280,7 @@ if (node.isInstrumentable()) { try { - final Instrument instrument = Instrument.create(eventListener, "NodeExecCounter"); + final Instrument instrument = Instrument.create(instrumentListener, "NodeExecCounter"); instruments.add(instrument); node.probe().attach(instrument); } catch (ProbeException ex) { @@ -304,7 +304,7 @@ @Override public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) { if (countingTag == tag) { - final Instrument instrument = Instrument.create(eventListener, NodeExecCounter.class.getSimpleName()); + final Instrument instrument = Instrument.create(instrumentListener, NodeExecCounter.class.getSimpleName()); instruments.add(instrument); probe.attach(instrument); } diff -r b950967f74c7 -r 87c62a38f843 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Tue Mar 17 12:05:49 2015 +0100 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Tue Mar 17 12:13:24 2015 +0100 @@ -36,10 +36,8 @@ import org.junit.runners.*; import org.junit.runners.model.*; -import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.instrument.impl.*; -import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.factory.*; import com.oracle.truffle.sl.nodes.instrument.*; @@ -271,12 +269,12 @@ } /** - * This sample instrument listener provides prints the value of an assignment (after the - * assignment is complete) to the {@link PrintStream} specified in the constructor. This - * instrument can only be attached to a wrapped {@link SLWriteLocalVariableNode}, but provides - * no guards to protect it from being attached elsewhere. + * This sample listener provides prints the value of an assignment (after the assignment is + * complete) to the {@link PrintStream} specified in the constructor. This listener can only be + * attached at {@link SLWriteLocalVariableNode}, but provides no guards to protect it from being + * attached elsewhere. */ - public final class SLPrintAssigmentValueListener extends DefaultEventListener { + public final class SLPrintAssigmentValueListener extends DefaultInstrumentListener { private PrintStream output; @@ -285,7 +283,7 @@ } @Override - public void returnValue(Node node, VirtualFrame frame, Object result) { + public void returnValue(Probe probe, Object result) { output.println(result); } } diff -r b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 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:49 2015 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java Tue Mar 17 12:13:24 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 b950967f74c7 -r 87c62a38f843 mxtool/mx.py --- a/mxtool/mx.py Tue Mar 17 12:05:49 2015 +0100 +++ b/mxtool/mx.py Tue Mar 17 12:13:24 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}) diff -r b950967f74c7 -r 87c62a38f843 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Tue Mar 17 12:05:49 2015 +0100 +++ b/src/share/vm/opto/compile.cpp Tue Mar 17 12:13:24 2015 +0100 @@ -2184,6 +2184,8 @@ if (failing()) return; } } + // Ensure that major progress is now clear + C->clear_major_progress(); { // Verify that all previous optimizations produced a valid graph