# HG changeset patch # User Christian Humer # Date 1362153968 -3600 # Node ID 8fa2eed07f81fa7d970af26223d68d305f5a26c2 # Parent 0b48dc5f37c3fd2b9c1d728dc61deb6e1e9fe890# Parent 748cb57f53cb6dde5b16389e6d7da0ca54a89bdd Merge. diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java Fri Mar 01 17:06:08 2013 +0100 @@ -32,17 +32,6 @@ private static final long serialVersionUID = -1003772042519945089L; - /** - * A sentinel value used as a place holder in an instruction stream for an address that will be - * patched. - */ - /* - * @SuppressWarnings("serial") public static final Address Placeholder = new - * Address(Kind.Illegal) { - * - * @Override public String toString() { return "[]"; } }; - */ - public Address(Kind kind) { super(kind); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java Fri Mar 01 17:06:08 2013 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, 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.api.code; + +import com.oracle.graal.api.meta.*; + +/** + * Common base class for values that can be manipulated by the register allocator. + */ +public abstract class AllocatableValue extends Value { + + private static final long serialVersionUID = 153019506717492133L; + + /** + * Marker to tell the register allocator that no storage location needs to be allocated for this + * value. + */ + @SuppressWarnings("serial") public static final AllocatableValue UNUSED = new AllocatableValue(Kind.Illegal) { + + @Override + public String toString() { + return "-"; + } + }; + + public AllocatableValue(Kind kind) { + super(kind); + } + +} diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Fri Mar 01 17:06:08 2013 +0100 @@ -23,9 +23,6 @@ package com.oracle.graal.api.code; import java.nio.*; -import java.util.*; - -import com.oracle.graal.api.code.Register.RegisterFlag; /** * Represents a CPU architecture, including information such as its endianness, CPU registers, word @@ -79,22 +76,6 @@ */ private final int returnAddressSize; - private final EnumMap registersByTypeAndEncoding; - - /** - * Gets the register for a given {@linkplain Register#encoding encoding} and type. - * - * @param encoding a register value as used in a machine instruction - * @param type the type of the register - */ - public Register registerFor(int encoding, RegisterFlag type) { - Register[] regs = registersByTypeAndEncoding.get(type); - assert encoding >= 0 && encoding < regs.length; - Register reg = regs[encoding]; - assert reg != null; - return reg; - } - protected Architecture(String name, int wordSize, ByteOrder byteOrder, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset, int registerReferenceMapBitCount, int returnAddressSize) { this.name = name; @@ -105,18 +86,6 @@ this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset; this.registerReferenceMapBitCount = registerReferenceMapBitCount; this.returnAddressSize = returnAddressSize; - - registersByTypeAndEncoding = new EnumMap<>(RegisterFlag.class); - EnumMap categorizedRegs = Register.categorize(registers); - for (RegisterFlag type : RegisterFlag.values()) { - Register[] regs = categorizedRegs.get(type); - int max = Register.maxRegisterEncoding(regs); - Register[] regsByEnc = new Register[max + 1]; - for (Register reg : regs) { - regsByEnc[reg.encoding] = reg; - } - registersByTypeAndEncoding.put(type, regsByEnc); - } } /** @@ -161,14 +130,6 @@ } /** - * Gets a mask of the barrier constants denoting the barriers that are not required to be - * explicitly inserted under this architecture. - */ - public int getImplicitMemoryBarriers() { - return implicitMemoryBarriers; - } - - /** * Gets the size of the return address pushed to the stack by a call instruction. A value of 0 * denotes that call linkage uses registers instead. */ diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java Fri Mar 01 17:06:08 2013 +0100 @@ -30,7 +30,7 @@ * {@link Register#asValue(Kind)} to retrieve the canonical {@link RegisterValue} instance for a * given (register,kind) pair. */ -public final class RegisterValue extends Value { +public final class RegisterValue extends AllocatableValue { private static final long serialVersionUID = 7999341472196897163L; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java Fri Mar 01 17:06:08 2013 +0100 @@ -30,7 +30,7 @@ * Represents a compiler spill slot or an outgoing stack-based argument in a method's frame or an * incoming stack-based argument in a method's {@linkplain #isInCallerFrame() caller's frame}. */ -public final class StackSlot extends Value { +public final class StackSlot extends AllocatableValue { private static final long serialVersionUID = -7725071921307318433L; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java Fri Mar 01 17:06:08 2013 +0100 @@ -58,6 +58,16 @@ return (Constant) value; } + public static boolean isAllocatableValue(Value value) { + assert value != null; + return value instanceof AllocatableValue; + } + + public static AllocatableValue asAllocatableValue(Value value) { + assert value != null; + return (AllocatableValue) value; + } + public static boolean isStackSlot(Value value) { assert value != null; return value instanceof StackSlot; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Fri Mar 01 17:06:08 2013 +0100 @@ -25,8 +25,8 @@ import static com.oracle.graal.api.code.ValueUtil.*; 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.AMD64BitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.amd64.AMD64MathIntrinsicOp.IntrinsicOpcode.*; import com.oracle.graal.amd64.*; @@ -41,11 +41,12 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivOp; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Reg; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Stack; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp; import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Reg; import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Stack; import com.oracle.graal.lir.amd64.AMD64Arithmetic.ShiftOp; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; import com.oracle.graal.lir.amd64.AMD64Call.IndirectCallOp; @@ -66,10 +67,11 @@ import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; import com.oracle.graal.lir.amd64.AMD64Move.NullCheckOp; import com.oracle.graal.lir.amd64.AMD64Move.SpillMoveOp; +import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; +import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp; import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.util.*; @@ -137,68 +139,14 @@ } @Override - public Address makeAddress(Kind kind, Value base, int displacement) { - return new AMD64Address(kind, base, displacement); - } - - @Override - public Address makeAddress(LocationNode location, ValueNode object) { - Value base = operand(object); - Value index = Value.ILLEGAL; - int scale = 1; - int displacement = location.displacement(); - - if (isConstant(base)) { - if (asConstant(base).isNull()) { - base = Value.ILLEGAL; - } else if (asConstant(base).getKind() != Kind.Object) { - long newDisplacement = displacement + asConstant(base).asLong(); - if (NumUtil.isInt(newDisplacement)) { - assert !runtime.needsDataPatch(asConstant(base)); - displacement = (int) newDisplacement; - base = Value.ILLEGAL; - } else { - Value newBase = newVariable(Kind.Long); - emitMove(base, newBase); - base = newBase; - } - } - } - - if (location instanceof IndexedLocationNode) { - IndexedLocationNode indexedLoc = (IndexedLocationNode) location; - - index = operand(indexedLoc.index()); - scale = indexedLoc.indexScaling(); - if (isConstant(index)) { - long newDisplacement = displacement + asConstant(index).asLong() * scale; - // only use the constant index if the resulting displacement fits into a 32 bit - // offset - if (NumUtil.isInt(newDisplacement)) { - displacement = (int) newDisplacement; - index = Value.ILLEGAL; - } else { - // create a temporary variable for the index, the pointer load cannot handle a - // constant index - Value newIndex = newVariable(Kind.Long); - emitMove(index, newIndex); - index = newIndex; - } - } - } - - return new AMD64Address(location.getValueKind(), base, index, AMD64Address.Scale.fromInt(scale), displacement); - } - - @Override public Variable emitMove(Value input) { Variable result = newVariable(input.getKind()); - emitMove(input, result); + emitMove(result, input); return result; } @Override - public void emitMove(Value src, Value dst) { + public void emitMove(Value dst, Value src) { if (isRegister(src) || isStackSlot(dst)) { append(new MoveFromRegOp(dst, src)); } else { @@ -206,27 +154,94 @@ } } + private AMD64Address prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) { + Value baseRegister = base; + int finalDisp = displacement; + if (isConstant(base)) { + if (asConstant(base).isNull()) { + baseRegister = Value.ILLEGAL; + } else if (asConstant(base).getKind() != Kind.Object) { + long newDisplacement = displacement + asConstant(base).asLong(); + if (NumUtil.isInt(newDisplacement)) { + assert !runtime.needsDataPatch(asConstant(base)); + finalDisp = (int) newDisplacement; + baseRegister = Value.ILLEGAL; + } else { + Value newBase = newVariable(Kind.Long); + emitMove(newBase, base); + baseRegister = newBase; + } + } + } + + Value indexRegister = index; + AMD64Address.Scale scaleEnum; + if (index != Value.ILLEGAL && scale > 0) { + scaleEnum = AMD64Address.Scale.fromInt(scale); + if (isConstant(index)) { + long newDisplacement = finalDisp + asConstant(index).asLong() * scale; + // only use the constant index if the resulting displacement fits into a 32 bit + // offset + if (NumUtil.isInt(newDisplacement)) { + finalDisp = (int) newDisplacement; + indexRegister = Value.ILLEGAL; + } else { + // create a temporary variable for the index, the pointer load cannot handle a + // constant index + Value newIndex = newVariable(Kind.Long); + emitMove(newIndex, index); + indexRegister = newIndex; + } + } + } else { + indexRegister = Value.ILLEGAL; + scaleEnum = AMD64Address.Scale.Times1; + } + + return new AMD64Address(kind, baseRegister, indexRegister, scaleEnum, finalDisp); + } + @Override - public Variable emitLoad(Value loadAddress, boolean canTrap) { + public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { + AMD64Address loadAddress = prepareAddress(kind, base, displacement, index, scale); Variable result = newVariable(loadAddress.getKind()); append(new LoadOp(result, loadAddress, canTrap ? state() : null)); return result; } @Override - public void emitStore(Value storeAddress, Value inputVal, boolean canTrap) { - Value input = loadForStore(inputVal, storeAddress.getKind()); - append(new StoreOp(storeAddress, input, canTrap ? state() : null)); + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) { + AMD64Address storeAddress = prepareAddress(kind, base, displacement, index, scale); + LIRFrameState state = canTrap ? state() : null; + + if (isConstant(inputVal)) { + Constant c = asConstant(inputVal); + if (canStoreConstant(c)) { + append(new StoreConstantOp(storeAddress, c, state)); + return; + } + } + + Variable input = load(inputVal); + append(new StoreOp(storeAddress, input, state)); } @Override - public Variable emitLea(Value address) { + public Variable emitLea(Value base, int displacement, Value index, int scale) { Variable result = newVariable(target().wordKind); + AMD64Address address = prepareAddress(result.getKind(), base, displacement, index, scale); append(new LeaOp(result, address)); return result; } @Override + public Variable emitLea(StackSlot address) { + Variable result = newVariable(target().wordKind); + append(new StackLeaOp(result, address)); + return result; + } + + @Override public void emitJump(LabelRef label, LIRFrameState info) { append(new JumpOp(label, info)); } @@ -339,14 +354,15 @@ } @Override - public Variable emitNegate(Value input) { + public Variable emitNegate(Value inputVal) { + AllocatableValue input = asAllocatable(inputVal); Variable result = newVariable(input.getKind()); switch (input.getKind()) { case Int: - append(new Op1Stack(INEG, result, input)); + append(new Unary1Op(INEG, result, input)); break; case Long: - append(new Op1Stack(LNEG, result, input)); + append(new Unary1Op(LNEG, result, input)); break; case Float: append(new Op2Reg(FXOR, result, input, Constant.forFloat(Float.intBitsToFloat(0x80000000)))); @@ -456,11 +472,11 @@ public Value[] emitIntegerDivRem(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); + emitMove(RAX_I, a); append(new DivRemOp(IDIVREM, RAX_I, load(b), state())); return new Value[]{emitMove(RAX_I), emitMove(RDX_I)}; case Long: - emitMove(a, RAX_L); + emitMove(RAX_L, a); append(new DivRemOp(LDIVREM, RAX_L, load(b), state())); return new Value[]{emitMove(RAX_L), emitMove(RDX_L)}; default: @@ -472,11 +488,11 @@ public Value emitDiv(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); + emitMove(RAX_I, a); append(new DivOp(IDIV, RAX_I, RAX_I, load(b), state())); return emitMove(RAX_I); case Long: - emitMove(a, RAX_L); + emitMove(RAX_L, a); append(new DivOp(LDIV, RAX_L, RAX_L, load(b), state())); return emitMove(RAX_L); case Float: { @@ -498,11 +514,11 @@ public Value emitRem(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); + emitMove(RAX_I, a); append(new DivOp(IREM, RDX_I, RAX_I, load(b), state())); return emitMove(RDX_I); case Long: - emitMove(a, RAX_L); + emitMove(RAX_L, a); append(new DivOp(LREM, RDX_L, RAX_L, load(b), state())); return emitMove(RDX_L); case Float: { @@ -522,11 +538,11 @@ public Variable emitUDiv(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); + emitMove(RAX_I, a); append(new DivOp(IUDIV, RAX_I, RAX_I, load(b), state())); return emitMove(RAX_I); case Long: - emitMove(a, RAX_L); + emitMove(RAX_L, a); append(new DivOp(LUDIV, RAX_L, RAX_L, load(b), state())); return emitMove(RAX_L); default: @@ -538,11 +554,11 @@ public Variable emitURem(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); + emitMove(RAX_I, a); append(new DivOp(IUREM, RDX_I, RAX_I, load(b), state())); return emitMove(RDX_I); case Long: - emitMove(a, RAX_L); + emitMove(RAX_L, a); append(new DivOp(LUREM, RDX_L, RAX_L, load(b), state())); return emitMove(RDX_L); default: @@ -651,7 +667,7 @@ return value; } // Non-constant shift count must be in RCX - emitMove(value, RCX_I); + emitMove(RCX_I, value); return RCX_I; } @@ -661,67 +677,67 @@ Variable result = newVariable(opcode.to); switch (opcode) { case I2L: - append(new Op1Reg(I2L, result, input)); + append(new Unary2Op(I2L, result, input)); break; case L2I: - append(new Op1Stack(L2I, result, input)); + append(new Unary1Op(L2I, result, input)); break; case I2B: - append(new Op1Stack(I2B, result, input)); + append(new Unary2Op(I2B, result, input)); break; case I2C: - append(new Op1Stack(I2C, result, input)); + append(new Unary1Op(I2C, result, input)); break; case I2S: - append(new Op1Stack(I2S, result, input)); + append(new Unary2Op(I2S, result, input)); break; case F2D: - append(new Op1Reg(F2D, result, input)); + append(new Unary2Op(F2D, result, input)); break; case D2F: - append(new Op1Reg(D2F, result, input)); + append(new Unary2Op(D2F, result, input)); break; case I2F: - append(new Op1Reg(I2F, result, input)); + append(new Unary2Op(I2F, result, input)); break; case I2D: - append(new Op1Reg(I2D, result, input)); + append(new Unary2Op(I2D, result, input)); break; case F2I: - append(new Op1Reg(F2I, result, input)); + append(new Unary2Op(F2I, result, input)); break; case D2I: - append(new Op1Reg(D2I, result, input)); + append(new Unary2Op(D2I, result, input)); break; case L2F: - append(new Op1Reg(L2F, result, input)); + append(new Unary2Op(L2F, result, input)); break; case L2D: - append(new Op1Reg(L2D, result, input)); + append(new Unary2Op(L2D, result, input)); break; case F2L: - append(new Op1Reg(F2L, result, input)); + append(new Unary2Op(F2L, result, input)); break; case D2L: - append(new Op1Reg(D2L, result, input)); + append(new Unary2Op(D2L, result, input)); break; case MOV_I2F: - append(new Op1Reg(MOV_I2F, result, input)); + append(new Unary2Op(MOV_I2F, result, input)); break; case MOV_L2D: - append(new Op1Reg(MOV_L2D, result, input)); + append(new Unary2Op(MOV_L2D, result, input)); break; case MOV_F2I: - append(new Op1Reg(MOV_F2I, result, input)); + append(new Unary2Op(MOV_F2I, result, input)); break; case MOV_D2L: - append(new Op1Reg(MOV_D2L, result, input)); + append(new Unary2Op(MOV_D2L, result, input)); break; case UNSIGNED_I2L: // Instructions that move or generate 32-bit register values also set the upper 32 // bits of the register to zero. // Consequently, there is no need for a special zero-extension move. - emitMove(input, result); + emitMove(result, input); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -761,7 +777,7 @@ // The current register allocator cannot handle variables at call sites, need a fixed // register. Value targetAddress = AMD64.rax.asValue(); - emitMove(operand(callTarget.computedAddress()), targetAddress); + emitMove(targetAddress, operand(callTarget.computedAddress())); append(new IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState)); } @@ -777,23 +793,23 @@ @Override public void emitBitCount(Variable result, Value value) { if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(IPOPCNT, result, value)); + append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LPOPCNT, result, value)); + append(new AMD64BitManipulationOp(LPOPCNT, result, asAllocatable(value))); } } @Override public void emitBitScanForward(Variable result, Value value) { - append(new AMD64BitManipulationOp(BSF, result, value)); + append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value))); } @Override public void emitBitScanReverse(Variable result, Value value) { if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(IBSR, result, value)); + append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LBSR, result, value)); + append(new AMD64BitManipulationOp(LBSR, result, asAllocatable(value))); } } @@ -885,7 +901,7 @@ Value expected = loadNonConst(operand(node.expected())); Variable newValue = load(operand(node.newValue())); - Address address; + AMD64Address address; int displacement = node.displacement(); Value index = operand(node.offset()); if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong() + displacement)) { @@ -897,7 +913,7 @@ } RegisterValue rax = AMD64.rax.asValue(kind); - emitMove(expected, rax); + emitMove(rax, expected); append(new CompareAndSwapOp(rax, address, rax, newValue)); Variable result = newVariable(node.kind()); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Fri Mar 01 17:06:08 2013 +0100 @@ -50,7 +50,6 @@ import com.oracle.graal.lir.ptx.PTXMove.StoreOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.ptx.*; @@ -100,55 +99,14 @@ } @Override - public Address makeAddress(Kind kind, Value base, int displacement) { - return new PTXAddress(kind, base, displacement); - } - - @Override - public Address makeAddress(LocationNode location, ValueNode object) { - Value base = operand(object); - long displacement = location.displacement(); - - if (isConstant(base)) { - if (asConstant(base).isNull()) { - base = Value.ILLEGAL; - } else if (asConstant(base).getKind() != Kind.Object) { - displacement += asConstant(base).asLong(); - base = Value.ILLEGAL; - } - } - - if (location instanceof IndexedLocationNode) { - IndexedLocationNode indexedLoc = (IndexedLocationNode) location; - - Value index = operand(indexedLoc.index()); - int scale = indexedLoc.indexScaling(); - if (isConstant(index)) { - displacement += asConstant(index).asLong() * scale; - } else { - if (scale != 1) { - index = emitMul(index, Constant.forInt(scale)); - } - if (base == Value.ILLEGAL) { - base = index; - } else { - base = emitAdd(base, index); - } - } - } - - return new PTXAddress(location.getValueKind(), base, displacement); - } - - @Override public Variable emitMove(Value input) { Variable result = newVariable(input.getKind()); - emitMove(input, result); + emitMove(result, input); return result; } @Override - public void emitMove(Value src, Value dst) { + public void emitMove(Value dst, Value src) { if (isRegister(src) || isStackSlot(dst)) { append(new MoveFromRegOp(dst, src)); } else { @@ -156,21 +114,59 @@ } } + private PTXAddress prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) { + Value baseRegister = base; + long finalDisp = displacement; + if (isConstant(base)) { + if (asConstant(base).isNull()) { + baseRegister = Value.ILLEGAL; + } else if (asConstant(base).getKind() != Kind.Object) { + finalDisp += asConstant(base).asLong(); + baseRegister = Value.ILLEGAL; + } + } + + if (index != Value.ILLEGAL) { + if (isConstant(index)) { + finalDisp += asConstant(index).asLong() * scale; + } else { + Value indexRegister = index; + if (scale != 1) { + indexRegister = emitMul(index, Constant.forInt(scale)); + } + if (baseRegister == Value.ILLEGAL) { + baseRegister = indexRegister; + } else { + baseRegister = emitAdd(baseRegister, indexRegister); + } + } + } + + return new PTXAddress(kind, baseRegister, finalDisp); + } + @Override - public Variable emitLoad(Value loadAddress, boolean canTrap) { + public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { + PTXAddress loadAddress = prepareAddress(kind, base, displacement, index, scale); Variable result = newVariable(loadAddress.getKind()); append(new LoadOp(result, loadAddress, canTrap ? state() : null)); return result; } @Override - public void emitStore(Value storeAddress, Value inputVal, boolean canTrap) { - Value input = loadForStore(inputVal, storeAddress.getKind()); + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) { + PTXAddress storeAddress = prepareAddress(kind, base, displacement, index, scale); + Variable input = load(inputVal); append(new StoreOp(storeAddress, input, canTrap ? state() : null)); } @Override - public Variable emitLea(Value address) { + public Variable emitLea(Value base, int displacement, Value index, int scale) { + throw new InternalError("NYI"); + } + + @Override + public Variable emitLea(StackSlot address) { throw new InternalError("NYI"); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Fri Mar 01 17:06:08 2013 +0100 @@ -31,7 +31,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.ConvertNode.Op; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; /** @@ -215,36 +214,31 @@ } @Override - public Address makeAddress(Kind kind, Value base, int displacement) { - return null; + public void emitMove(Value dst, Value src) { + // SPARC: Auto-generated method stub + } @Override - public Address makeAddress(LocationNode location, ValueNode object) { + public Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { // SPARC: Auto-generated method stub return null; } @Override - public void emitMove(Value src, Value dst) { + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap) { // SPARC: Auto-generated method stub } @Override - public Value emitLoad(Value loadAddress, boolean canTrap) { + public Value emitLea(Value base, int displacement, Value index, int scale) { // SPARC: Auto-generated method stub return null; } @Override - public void emitStore(Value storeAddress, Value input, boolean canTrap) { - // SPARC: Auto-generated method stub - - } - - @Override - public Value emitLea(Value address) { + public Value emitLea(StackSlot address) { // SPARC: Auto-generated method stub return null; } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java Fri Mar 01 17:06:08 2013 +0100 @@ -112,7 +112,7 @@ Method method = CompilableObjectImpl.class.getDeclaredMethod("executeHelper", ObjectCompiler.class, String.class); ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.NONE).apply(graph); new CanonicalizerPhase(runtime, new Assumptions(false)).apply(graph); new DeadCodeEliminationPhase().apply(graph); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Fri Mar 01 17:06:08 2013 +0100 @@ -407,7 +407,7 @@ protected StructuredGraph parse(Method m) { ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(m); StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); return graph; } @@ -423,7 +423,7 @@ protected PhasePlan getDefaultPhasePlan() { PhasePlan plan = new PhasePlan(); - plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL)); + plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL)); return plan; } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Fri Mar 01 17:06:08 2013 +0100 @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2011, 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.compiler.test; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.schedule.*; + +/** + * In these test the FrameStates are explicitly cleared out, so that the scheduling of + * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the + * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the + * right thing. + * + * The scheduling shouldn't depend on FrameStates, which is tested by this class. + */ +public class MemoryScheduleTest extends GraphScheduleTest { + + private static enum TestMode { + WITH_FRAMESTATES, WITHOUT_FRAMESTATES, INLINED_WITHOUT_FRAMESTATES + } + + public static class Container { + + public int a; + public int b; + public int c; + } + + private static final Container container = new Container(); + + /** + * In this test the read should be scheduled before the write. + */ + public static int testSimpleSnippet() { + try { + return container.a; + } finally { + container.a = 15; + } + } + + @Test + public void testSimple() { + for (TestMode mode : TestMode.values()) { + SchedulePhase schedule = getFinalSchedule("testSimpleSnippet", mode); + assertReadAfterWrite(schedule, false); + } + } + + /** + * In this case the read should be scheduled in the first block. + */ + public static int testSplitSnippet1(int a) { + try { + return container.a; + } finally { + if (a < 0) { + container.a = 15; + } else { + container.b = 15; + } + } + } + + @Test + public void testSplit1() { + for (TestMode mode : TestMode.values()) { + SchedulePhase schedule = getFinalSchedule("testSplitSnippet1", mode); + assertReadWithinStartBlock(schedule, true); + } + } + + /** + * Here the read should float to the end. + */ + public static int testSplit2Snippet(int a) { + try { + return container.a; + } finally { + if (a < 0) { + container.c = 15; + } else { + container.b = 15; + } + } + } + + @Test + public void testSplit2() { + SchedulePhase schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES); + assertReadWithinStartBlock(schedule, false); + } + + /** + * Here the read should not float to the end. + */ + public static int testLoop1Snippet(int a, int b) { + try { + return container.a; + } finally { + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + } else { + container.a = 15; + } + } + } + } + + @Test + public void testLoop1() { + SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); + assertEquals(7, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, true); + } + + /** + * Here the read should float to the end. + */ + public static int testLoop2Snippet(int a, int b) { + try { + return container.a; + } finally { + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + } else { + container.c = 15; + } + } + } + } + + @Test + public void testLoop2() { + SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); + assertEquals(7, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(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) { + System.arraycopy(a, 0, b, 0, len); + return intValue.intValue(); + } + + @Test + public void testArrayCopy() { + SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); + StructuredGraph graph = (StructuredGraph) schedule.getCFG().getStartBlock().getBeginNode().graph(); + ReturnNode ret = graph.getNodes(ReturnNode.class).first(); + assertTrue(ret.result() instanceof FloatingReadNode); + assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); + } + + private void assertReadAfterWrite(SchedulePhase schedule, boolean readAfterWrite) { + boolean writeEncountered = false; + assertEquals(1, schedule.getCFG().getBlocks().length); + for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { + if (node instanceof WriteNode) { + writeEncountered = true; + } else if (node instanceof FloatingReadNode) { + assertEquals(readAfterWrite, writeEncountered); + } + } + } + + private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) { + boolean readEncountered = false; + for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { + if (node instanceof FloatingReadNode) { + readEncountered = true; + } + } + assertEquals(withinStartBlock, readEncountered); + } + + private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode) { + return Debug.scope("FloatingReadTest", new DebugDumpScope(snippet), new Callable() { + + @Override + public SchedulePhase call() throws Exception { + StructuredGraph graph = parse(snippet); + if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { + Assumptions assumptions = new Assumptions(false); + new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + } + new LoweringPhase(null, runtime(), new Assumptions(false)).apply(graph); + if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { + for (Node node : graph.getNodes()) { + if (node instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) node).stateAfter(); + if (stateAfter != null) { + ((StateSplit) node).setStateAfter(null); + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } + } + } + } + new FloatingReadPhase().apply(graph); + + new RemoveValueProxyPhase().apply(graph); + + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph); + return schedule; + } + }); + } +} diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Fri Mar 01 17:06:08 2013 +0100 @@ -117,7 +117,7 @@ new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph); new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.CheckCastElimination && GraalOptions.OptCanonicalizer) { + if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { new CanonicalizerPhase(runtime, assumptions).apply(graph); new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); } @@ -181,7 +181,7 @@ new EliminatePartiallyRedundantGuardsPhase(false, true).apply(graph); } - if (GraalOptions.CheckCastElimination && GraalOptions.OptCanonicalizer) { + if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Mar 01 17:06:08 2013 +0100 @@ -90,6 +90,16 @@ */ private final ArrayList lockDataSlots; + /** + * Checks whether the supplied constant can be used without loading it into a register for store + * operations, i.e., on the right hand side of a memory access. + * + * @param c The constant to check. + * @return True if the constant can be used directly, false if the constant needs to be in a + * register. + */ + public abstract boolean canStoreConstant(Constant c); + public LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { this.graph = graph; this.runtime = runtime; @@ -183,6 +193,14 @@ @Override public abstract Variable emitMove(Value input); + public AllocatableValue asAllocatable(Value value) { + if (isAllocatableValue(value)) { + return asAllocatableValue(value); + } else { + return emitMove(value); + } + } + public Variable load(Value value) { if (!isVariable(value)) { return emitMove(value); @@ -197,18 +215,6 @@ return value; } - public Value loadForStore(Value value, Kind storeKind) { - if (isConstant(value) && canStoreConstant((Constant) value)) { - return value; - } - if (storeKind == Kind.Byte || storeKind == Kind.Boolean) { - Variable tempVar = new Variable(value.getKind(), lir.nextVariable(), Register.RegisterFlag.Byte); - emitMove(value, tempVar); - return tempVar; - } - return load(value); - } - protected LabelRef getLIRBlock(FixedNode b) { Block result = lir.cfg.blockFor(b); int suxIndex = currentBlock.getSuccessors().indexOf(result); @@ -525,7 +531,7 @@ Value operand = Value.ILLEGAL; if (x.result() != null) { operand = resultOperandFor(x.result().kind()); - emitMove(operand(x.result()), operand); + emitMove(operand, operand(x.result())); } emitReturn(operand); } @@ -747,7 +753,7 @@ for (ValueNode arg : arguments) { if (arg != null) { Value operand = toStackKind(cc.getArgument(j)); - emitMove(operand(arg), operand); + emitMove(operand, operand(arg)); result[j] = operand; j++; } else { @@ -770,7 +776,7 @@ for (int i = 0; i < args.length; i++) { Value arg = args[i]; Value loc = cc.getArgument(i); - emitMove(arg, loc); + emitMove(loc, arg); argLocations[i] = loc; } emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), Constant.forLong(0), info); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Fri Mar 01 17:06:08 2013 +0100 @@ -187,7 +187,7 @@ private void emitMove(Value src, Value dest) { assert isLegal(src); assert isLegal(dest); - gen.emitMove(src, dest); + gen.emitMove(dest, src); } // Traverse assignment graph in depth first order and generate moves in post order diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Fri Mar 01 17:06:08 2013 +0100 @@ -72,6 +72,10 @@ assert !isNew(node) : "this node was added to the graph after creating the node map : " + node; } + public void clear() { + Arrays.fill(values, null); + } + public Iterable> entries() { return new Iterable>() { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Fri Mar 01 17:06:08 2013 +0100 @@ -112,11 +112,9 @@ public void visitExceptionObject(ExceptionObjectNode x) { HotSpotVMConfig config = runtime().config; RegisterValue thread = runtime().threadRegister().asValue(); - Address exceptionAddress = new AMD64Address(Kind.Object, thread, config.threadExceptionOopOffset); - Address pcAddress = new AMD64Address(Kind.Long, thread, config.threadExceptionPcOffset); - Value exception = emitLoad(exceptionAddress, false); - emitStore(exceptionAddress, Constant.NULL_OBJECT, false); - emitStore(pcAddress, Constant.LONG_0, false); + Value exception = emitLoad(Kind.Object, thread, config.threadExceptionOopOffset, Value.ILLEGAL, 0, false); + emitStore(Kind.Object, thread, config.threadExceptionOopOffset, Value.ILLEGAL, 0, Constant.NULL_OBJECT, false); + emitStore(Kind.Long, thread, config.threadExceptionPcOffset, Value.ILLEGAL, 0, Constant.LONG_0, false); setResult(x, exception); } @@ -130,7 +128,7 @@ Variable newVal = load(operand(x.newValue())); int disp = 0; - Address address; + AMD64Address address; Value index = operand(x.offset()); if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) { assert !runtime.needsDataPatch(asConstant(index)); @@ -141,11 +139,11 @@ } RegisterValue rax = AMD64.rax.asValue(kind); - emitMove(expected, rax); + emitMove(rax, expected); append(new CompareAndSwapOp(rax, address, rax, newVal)); Variable result = newVariable(x.kind()); - emitMove(rax, result); + emitMove(result, rax); setResult(x, result); } @@ -163,9 +161,9 @@ @Override protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { Value metaspaceMethod = AMD64.rbx.asValue(); - emitMove(operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()), metaspaceMethod); + emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod())); Value targetAddress = AMD64.rax.asValue(); - emitMove(operand(callTarget.computedAddress()), targetAddress); + emitMove(targetAddress, operand(callTarget.computedAddress())); append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java Fri Mar 01 17:06:08 2013 +0100 @@ -47,7 +47,7 @@ @Override public void generate(LIRGeneratorTool gen) { - Value addr = gen.emitLea(gen.makeAddress(location(), object())); + Value addr = location().generateLea(gen, object()); generateBarrier(addr, gen); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -52,6 +52,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void generate(LIRGenerator gen) { gen.lock(); StackSlot lockData = gen.peekLock(); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java Fri Mar 01 17:06:08 2013 +0100 @@ -42,7 +42,7 @@ public void generate(LIRGeneratorTool gen) { HotSpotGraalRuntime runtime = HotSpotGraalRuntime.getInstance(); Register thread = runtime.getRuntime().threadRegister(); - gen.setResult(this, gen.emitLoad(gen.makeAddress(Kind.Object, thread.asValue(gen.target().wordKind), runtime.getConfig().threadObjectOffset), false)); + gen.setResult(this, gen.emitLoad(Kind.Object, thread.asValue(gen.target().wordKind), runtime.getConfig().threadObjectOffset, Value.ILLEGAL, 0, false)); } @NodeIntrinsic diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -32,8 +32,8 @@ /** * A special purpose store node that differs from {@link CompareAndSwapNode} in that it is not a - * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word) returns} either - * the expected value or the compared against value instead of a boolean. + * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word, Object)} returns + * either the expected value or the compared against value instead of a boolean. */ public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint { @@ -42,17 +42,15 @@ @Input private ValueNode expectedValue; @Input private ValueNode newValue; - public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue) { + private final Object locationIdentity; + + public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Object locationIdentity) { super(expected.stamp()); this.object = object; this.offset = offset; this.expectedValue = expected; this.newValue = newValue; - } - - @Override - public void generate(LIRGenerator gen) { - ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this); + this.locationIdentity = locationIdentity; } public ValueNode object() { @@ -71,6 +69,16 @@ return newValue; } + @Override + public Object getLocationIdentity() { + return locationIdentity; + } + + @Override + public void generate(LIRGenerator gen) { + ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this); + } + /** * Compares an expected value with the actual value in a location denoted by an object and a * given offset. Iff they are same, {@code newValue} is placed into the location and the @@ -84,5 +92,5 @@ * @return either {@code expectedValue} or the actual value */ @NodeIntrinsic - public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue); + public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter Object locationIdentity); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -44,6 +44,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void generate(LIRGenerator gen) { gen.unlock(); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java Fri Mar 01 17:06:08 2013 +0100 @@ -41,7 +41,7 @@ @Override public void generate(LIRGeneratorTool generator) { Value obj = generator.newVariable(generator.target().wordKind); - generator.emitMove(generator.operand(object()), obj); + generator.emitMove(obj, generator.operand(object())); generateBarrier(obj, generator); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -47,7 +47,7 @@ @Override public void generate(LIRGeneratorTool gen) { Value obj = gen.newVariable(gen.target().wordKind); - gen.emitMove(gen.operand(object), obj); + gen.emitMove(obj, gen.operand(object)); gen.setResult(this, obj); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -54,7 +54,7 @@ // The register allocator would prefer us not to tie up an allocatable // register for the complete lifetime of this node. result = generator.newVariable(kind()); - generator.emitMove(register.asValue(kind()), result); + generator.emitMove(result, register.asValue(kind())); } else { result = register.asValue(kind()); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -69,7 +69,7 @@ parameters.add(frameState.localAt(slot)); } Value[] args = gen.visitInvokeArguments(cc, parameters); - Value entry = gen.emitLoad(gen.makeAddress(Kind.Long, gen.operand(target), config.nmethodEntryOffset), false); + Value entry = gen.emitLoad(Kind.Long, gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0, false); HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen; hsgen.emitTailcall(args, entry); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java Fri Mar 01 17:06:08 2013 +0100 @@ -45,6 +45,6 @@ } else { base = gen.emitAdd(base, Constant.forLong(config.cardtableStartAddress)); } - gen.emitStore(gen.makeAddress(Kind.Boolean, base, displacement), Constant.FALSE, false); + gen.emitStore(Kind.Boolean, base, displacement, Value.ILLEGAL, 0, Constant.FALSE, false); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -26,14 +26,16 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.RuntimeCallTarget.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.*; import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.java.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -43,6 +45,27 @@ public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class); + public class OSREntryProxyNode extends FloatingNode implements LIRLowerable { + + @Input private ValueNode object; + @Input(notDataflow = true) private final RuntimeCallNode anchor; + + public OSREntryProxyNode(ValueNode object, RuntimeCallNode anchor) { + super(object.stamp()); + this.object = object; + this.anchor = anchor; + } + + public RuntimeCallNode getAnchor() { + return anchor; + } + + @Override + public void generate(LIRGeneratorTool generator) { + generator.setResult(this, generator.operand(object)); + } + } + @Override protected void run(StructuredGraph graph) { if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { @@ -81,7 +104,7 @@ LoopTransformations.peel(osrLoop); for (Node usage : osr.usages().snapshot()) { - ValueProxyNode proxy = (ValueProxyNode) usage; + ProxyNode proxy = (ProxyNode) usage; proxy.replaceAndDelete(proxy.value()); } FixedNode next = osr.next(); @@ -108,15 +131,17 @@ start.setStateAfter(null); GraphUtil.killWithUnusedFloatingInputs(oldStartState); + // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) int localsOffset = (graph.method().getMaxLocals() - 1) * 8; for (int i = 0; i < osrState.localsSize(); i++) { ValueNode value = osrState.localAt(i); if (value != null) { - ValueProxyNode proxy = (ValueProxyNode) value; - int size = (value.kind() == Kind.Long || value.kind() == Kind.Double) ? 2 : 1; + ProxyNode proxy = (ProxyNode) value; + int size = FrameStateBuilder.stackSlots(value.kind()); int offset = localsOffset - (i + size - 1) * 8; UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), value.kind())); - proxy.replaceAndDelete(load); + OSREntryProxyNode newProxy = graph.add(new OSREntryProxyNode(load, migrationEnd)); + proxy.replaceAndDelete(newProxy); graph.addBeforeFixed(migrationEnd, load); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java Fri Mar 01 17:06:08 2013 +0100 @@ -70,7 +70,7 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { - Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset)).add(arrayBaseOffset(Kind.Byte)); + Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), UNKNOWN_LOCATION).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); if (encrypt) { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.snippets.nodes.*; @@ -59,21 +60,19 @@ return arguments.get(4); } - private ResolvedJavaMethod selectSnippet(LoweringTool tool) { + private StructuredGraph selectSnippet(LoweringTool tool) { ResolvedJavaType srcType = getSource().objectStamp().type(); ResolvedJavaType destType = getDestination().objectStamp().type(); - if (srcType != null && srcType.isArray() && destType != null && destType.isArray()) { - Kind componentKind = srcType.getComponentType().getKind(); - if (componentKind != Kind.Object) { - if (srcType.getComponentType() == destType.getComponentType()) { - return tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); - } - } else if (destType.getComponentType().isAssignableFrom(srcType.getComponentType()) && getDestination().objectStamp().isExactType()) { - return tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(Kind.Object)); - } + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + return null; } - return null; + if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType()) || !getDestination().objectStamp().isExactType()) { + return null; + } + Kind componentKind = srcType.getComponentType().getKind(); + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); + return (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); } private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) { @@ -88,27 +87,43 @@ new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); } + private static void replaceSnippetInvokes(StructuredGraph snippetGraph, ResolvedJavaMethod targetMethod, int bci) { + for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) { + if (invoke.methodCallTarget().targetMethod() != targetMethod) { + throw new GraalInternalError("unexpected invoke in arraycopy snippet"); + } + if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) { + InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), bci)); + newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI))); + snippetGraph.replaceFixedWithFixed(invoke, newInvoke); + } else { + assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke; + } + } + } + @Override - public void lower(LoweringTool tool) { - ResolvedJavaMethod snippetMethod = selectSnippet(tool); - if (snippetMethod == null) { - snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.increaseGenericCallCounterMethod); - // we will call the generic method. the generic snippet will only increase the counter, - // not call the actual method. therefore we create a second invoke here. - ((StructuredGraph) graph()).addAfterFixed(this, createInvoke()); - } - if (Debug.isLogEnabled()) { - Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType()); + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + if (!GraalOptions.IntrinsifyArrayCopy) { + return null; } - StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); - assert snippetGraph != null : "ArrayCopySnippets should be installed"; - if (getLength().isConstant()) { - snippetGraph = snippetGraph.copy(); - unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool); + StructuredGraph snippetGraph = selectSnippet(tool); + if (snippetGraph == null) { + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet); + snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class)).copy(); + assert snippetGraph != null : "ArrayCopySnippets should be installed"; + + replaceSnippetInvokes(snippetGraph, getTargetMethod(), getBci()); + } else { + assert snippetGraph != null : "ArrayCopySnippets should be installed"; + + if (getLength().isConstant()) { + snippetGraph = snippetGraph.copy(); + unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool); + } } - InvokeNode invoke = replaceWithInvoke(); - InliningUtil.inline(invoke, snippetGraph, false); + return snippetGraph; } private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Fri Mar 01 17:06:08 2013 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.snippets; -import static com.oracle.graal.api.code.DeoptimizationAction.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; @@ -33,24 +31,21 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; import com.oracle.graal.snippets.*; import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Fold; import com.oracle.graal.snippets.nodes.*; +import com.oracle.graal.word.*; @SuppressWarnings("unused") public class ArrayCopySnippets implements SnippetsInterface { private static final EnumMap arraycopyMethods = new EnumMap<>(Kind.class); - public static final Method increaseGenericCallCounterMethod; + public static final Method genericArraycopySnippet; private static void addArraycopySnippetMethod(Kind kind, Class arrayClass) throws NoSuchMethodException { arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); @@ -67,7 +62,7 @@ addArraycopySnippetMethod(Kind.Float, float[].class); addArraycopySnippetMethod(Kind.Double, double[].class); addArraycopySnippetMethod(Kind.Object, Object[].class); - increaseGenericCallCounterMethod = ArrayCopySnippets.class.getDeclaredMethod("increaseGenericCallCounter", Object.class, int.class, Object.class, int.class, int.class); + genericArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); } catch (SecurityException | NoSuchMethodException e) { throw new GraalInternalError(e); } @@ -81,7 +76,9 @@ private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); public static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter("baseKind") Kind baseKind) { - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); int header = arrayBaseOffset(baseKind); int elementSize = arrayIndexScale(baseKind); long byteLength = (long) length * elementSize; @@ -109,17 +106,24 @@ } } - public static void checkInputs(Object src, int srcPos, Object dest, int destPos, int length) { - if (src == null) { + public static void checkNonNull(Object obj) { + if (obj == null) { probability(DEOPT_PATH_PROBABILITY); checkNPECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } - if (dest == null) { + } + + public static int checkArrayType(Word hub) { + int layoutHelper = readLayoutHelper(hub); + if (layoutHelper >= 0) { probability(DEOPT_PATH_PROBABILITY); - checkNPECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } + return layoutHelper; + } + + public static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) { if (srcPos < 0) { probability(DEOPT_PATH_PROBABILITY); checkAIOOBECounter.inc(); @@ -187,7 +191,9 @@ @Snippet public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { longCounter.inc(); - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); Kind baseKind = Kind.Long; int header = arrayBaseOffset(baseKind); long byteLength = (long) length * arrayIndexScale(baseKind); @@ -209,7 +215,9 @@ @Snippet public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { doubleCounter.inc(); - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); Kind baseKind = Kind.Double; int header = arrayBaseOffset(baseKind); long byteLength = (long) length * arrayIndexScale(baseKind); @@ -232,7 +240,9 @@ @Snippet public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { objectCounter.inc(); - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); final int scale = arrayIndexScale(Kind.Object); int header = arrayBaseOffset(Kind.Object); if (src == dest && srcPos < destPos) { // bad aliased case @@ -262,12 +272,67 @@ } @Snippet - public static void increaseGenericCallCounter(Object src, int srcPos, Object dest, int destPos, int length) { - if (GraalOptions.SnippetCounters) { - if (src.getClass().getComponentType().isPrimitive()) { - genericPrimitiveCallCounter.inc(); - } else { - genericObjectCallCounter.inc(); + public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { + + // loading the hubs also checks for nullness + Word srcHub = loadHub(src); + Word destHub = loadHub(dest); + + int layoutHelper = checkArrayType(srcHub); + if (srcHub.equal(destHub) && src != dest) { + probability(FAST_PATH_PROBABILITY); + + checkLimits(src, srcPos, dest, destPos, length); + + arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); + } else { + genericObjectCallCounter.inc(); + System.arraycopy(src, srcPos, dest, destPos, length); + } + } + + public static void arraycopyInnerloop(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + + Word memory = (Word) Word.fromObject(src); + + Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); + Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); + Word destStart = destOffset; + long sizeInBytes = ((long) length) << log2ElementSize; + Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); + + int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); + Word destNonVectorEnd = destStart.add(nonVectorBytes); + + while (destOffset.belowThan(destNonVectorEnd)) { + destOffset.writeByte(0, srcOffset.readByte(0, UNKNOWN_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(1); + srcOffset = srcOffset.add(1); + } + while (destOffset.belowThan(destEnd)) { + destOffset.writeWord(0, srcOffset.readWord(0, UNKNOWN_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(wordSize()); + srcOffset = srcOffset.add(wordSize()); + } + + if ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) != 0) { + genericPrimitiveCallCounter.inc(); + + } else { + probability(LIKELY_PROBABILITY); + genericObjectExactCallCounter.inc(); + + if (length > 0) { + int cardShift = cardTableShift(); + long cardStart = cardTableStart(); + Word destCardOffset = destStart.unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); + Word destCardEnd = destEnd.subtract(1).unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); + while (destCardOffset.belowOrEqual(destCardEnd)) { + DirectStoreNode.store(destCardOffset.rawValue(), false, Kind.Boolean); + destCardOffset = destCardOffset.add(1); + } } } } @@ -287,7 +352,8 @@ private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays"); private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays"); private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays"); - private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "call to the generic, native arraycopy method"); + private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); + private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method"); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Fri Mar 01 17:06:08 2013 +0100 @@ -108,7 +108,7 @@ isNull.inc(); } else { Word objectHub = loadHub(object); - if (objectHub.readWord(superCheckOffset).notEqual(hub)) { + if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { probability(DEOPT_PATH_PROBABILITY); displayMiss.inc(); DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java Fri Mar 01 17:06:08 2013 +0100 @@ -66,7 +66,7 @@ @MethodSubstitution(isStatic = false) static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset)); + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION); if (getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); } else { @@ -75,8 +75,8 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { - Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset)).add(arrayBaseOffset(Kind.Byte)); - Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset)).add(arrayBaseOffset(Kind.Byte)); + Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), UNKNOWN_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), UNKNOWN_LOCATION).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); if (encrypt) { @@ -89,7 +89,7 @@ @MethodSubstitution(isStatic = false) static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset)); + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); } else { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java Fri Mar 01 17:06:08 2013 +0100 @@ -45,7 +45,7 @@ // Class for primitive type return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; } else { - return klass.readInt(klassModifierFlagsOffset()); + return klass.readInt(klassModifierFlagsOffset(), FINAL_LOCATION); } } @@ -55,7 +55,7 @@ if (klass.equal(0)) { return false; } else { - int accessFlags = klass.readInt(klassAccessFlagsOffset()); + int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); return (accessFlags & Modifier.INTERFACE) != 0; } } @@ -66,8 +66,7 @@ if (klass.equal(0)) { return false; } else { - int layoutHelper = klass.readInt(klassLayoutHelperOffset()); - return (layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0; + return (readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0; } } @@ -81,17 +80,16 @@ public static Class getSuperclass(final Class thisObj) { Word klass = loadWordFromObject(thisObj, klassOffset()); if (klass.notEqual(0)) { - int accessFlags = klass.readInt(klassAccessFlagsOffset()); + int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); if ((accessFlags & Modifier.INTERFACE) == 0) { - int layoutHelper = klass.readInt(klassLayoutHelperOffset()); - if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) { + if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { return Object.class; } else { - Word superKlass = klass.readWord(klassSuperKlassOffset()); + Word superKlass = klass.readWord(klassSuperKlassOffset(), FINAL_LOCATION); if (superKlass.equal(0)) { return null; } else { - return unsafeCast(superKlass.readObject(classMirrorOffset()), Class.class, true, true); + return unsafeCast(superKlass.readObject(classMirrorOffset(), FINAL_LOCATION), Class.class, true, true); } } } @@ -103,9 +101,8 @@ public static Class getComponentType(final Class thisObj) { Word klass = loadWordFromObject(thisObj, klassOffset()); if (klass.notEqual(0)) { - int layoutHelper = klass.readInt(klassLayoutHelperOffset()); - if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) { - return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset()), Class.class, true, true); + if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { + return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset(), FINAL_LOCATION), Class.class, true, true); } } return null; @@ -113,6 +110,6 @@ @MethodSubstitution(isStatic = false) public static boolean isInstance(final Class thisObj, Object obj) { - return !thisObj.isPrimitive() && ConditionalNode.materializeIsInstance(thisObj, obj); + return !isPrimitive(thisObj) && ConditionalNode.materializeIsInstance(thisObj, obj); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Fri Mar 01 17:06:08 2013 +0100 @@ -43,6 +43,10 @@ */ public class HotSpotSnippetUtils { + public static final Object ANY_LOCATION = LocationNode.ANY_LOCATION; + public static final Object UNKNOWN_LOCATION = LocationNode.UNKNOWN_LOCATION; + public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION; + public static HotSpotVMConfig config() { return HotSpotGraalRuntime.getInstance().getConfig(); } @@ -52,16 +56,49 @@ return config().verifyOops; } + public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop"); + @Fold public static int threadTlabTopOffset() { return config().threadTlabTopOffset; } + public static final Object TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd"); + @Fold - public static int threadTlabEndOffset() { + private static int threadTlabEndOffset() { return config().threadTlabEndOffset; } + public static final Object TLAB_START_LOCATION = LocationNode.createLocation("TlabStart"); + + @Fold + private static int threadTlabStartOffset() { + return config().threadTlabStartOffset; + } + + public static Word readTlabTop(Word thread) { + return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION); + } + + public static Word readTlabEnd(Word thread) { + return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION); + } + + public static Word readTlabStart(Word thread) { + return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION); + } + + public static void writeTlabTop(Word thread, Word top) { + thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION); + } + + public static void initializeTlab(Word thread, Word start, Word end) { + thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION); + thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION); + thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION); + } + @Fold public static int threadObjectOffset() { return config().threadObjectOffset; @@ -102,6 +139,8 @@ return Unsafe.getUnsafe().pageSize(); } + public static final Object PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord"); + @Fold public static int prototypeMarkWordOffset() { return config().prototypeMarkWordOffset; @@ -118,10 +157,14 @@ } @Fold - public static int klassLayoutHelperOffset() { + private static int klassLayoutHelperOffset() { return config().klassLayoutHelperOffset; } + public static int readLayoutHelper(Word hub) { + return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION); + } + @Fold public static int arrayKlassLayoutHelperIdentifier() { return config().arrayKlassLayoutHelperIdentifier; @@ -137,11 +180,25 @@ return config().klassSuperKlassOffset; } + public static final Object MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord"); + @Fold public static int markOffset() { return config().markOffset; } + public static final Object HUB_LOCATION = LocationNode.createLocation("Hub"); + + @Fold + private static int hubOffset() { + return config().hubOffset; + } + + public static void initializeObjectHeader(Word memory, Word markWord, Word hub) { + memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION); + memory.writeWord(hubOffset(), hub, HUB_LOCATION); + } + @Fold public static int unlockedMask() { return config().unlockedMask; @@ -188,11 +245,6 @@ } @Fold - public static int hubOffset() { - return config().hubOffset; - } - - @Fold public static int metaspaceArrayLengthOffset() { return config().metaspaceArrayLengthOffset; } @@ -232,16 +284,22 @@ return config().superCheckOffsetOffset; } + public static final Object SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache"); + @Fold public static int secondarySuperCacheOffset() { return config().secondarySuperCacheOffset; } + public static final Object SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers"); + @Fold public static int secondarySupersOffset() { return config().secondarySupersOffset; } + public static final Object DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord"); + @Fold public static int lockDisplacedMarkOffset() { return config().basicLockDisplacedHeaderOffset; @@ -308,12 +366,19 @@ return CodeUtil.log2(wordSize()); } + public static final Object CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState"); + @Fold public static int klassStateOffset() { return config().klassStateOffset; } @Fold + public static int klassStateFullyInitialized() { + return config().klassStateFullyInitialized; + } + + @Fold public static int klassModifierFlagsOffset() { return config().klassModifierFlagsOffset; } @@ -333,22 +398,21 @@ return config().klassInstanceSizeOffset; } + public static final Object HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop"); + @Fold public static long heapTopAddress() { return config().heapTopAddress; } + public static final Object HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd"); + @Fold public static long heapEndAddress() { return config().heapEndAddress; } @Fold - public static int threadTlabStartOffset() { - return config().threadTlabStartOffset; - } - - @Fold public static long tlabIntArrayMarkWord() { return config().tlabIntArrayMarkWord; } @@ -363,36 +427,43 @@ return config().tlabAlignmentReserve; } + public static final Object TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize"); + @Fold public static int threadTlabSizeOffset() { return config().threadTlabSizeOffset; } + public static final Object TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes"); + @Fold public static int threadAllocatedBytesOffset() { return config().threadAllocatedBytesOffset; } - @Fold - public static int klassStateFullyInitialized() { - return config().klassStateFullyInitialized; - } + public static final Object TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit"); @Fold public static int tlabRefillWasteLimitOffset() { return config().tlabRefillWasteLimitOffset; } + public static final Object TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills"); + @Fold public static int tlabNumberOfRefillsOffset() { return config().tlabNumberOfRefillsOffset; } + public static final Object TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste"); + @Fold public static int tlabFastRefillWasteOffset() { return config().tlabFastRefillWasteOffset; } + public static final Object TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations"); + @Fold public static int tlabSlowAllocationsOffset() { return config().tlabSlowAllocationsOffset; @@ -445,7 +516,6 @@ @Fold public static int layoutHelperElementTypePrimitiveInPlace() { - System.out.println(String.format("%x", config().layoutHelperElementTypePrimitiveInPlace)); return config().layoutHelperElementTypePrimitiveInPlace; } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Fri Mar 01 17:06:08 2013 +0100 @@ -99,7 +99,7 @@ return falseValue; } Word objectHub = loadHub(object); - if (objectHub.readWord(superCheckOffset).notEqual(hub)) { + if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { probability(NOT_LIKELY_PROBABILITY); displayMiss.inc(); return falseValue; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Fri Mar 01 17:06:08 2013 +0100 @@ -40,6 +40,7 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; @@ -109,7 +110,7 @@ // The bias pattern is present in the object's mark word. Need to check // whether the bias owner and the epoch are both still current. Word hub = loadHub(object); - final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); final Word thread = thread(); final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace()); trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord); @@ -154,7 +155,7 @@ Word biasedMark = unbiasedMark.or(thread); trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark).equal(unbiasedMark)) { + if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark)) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:acquired}", object); return; @@ -175,7 +176,7 @@ // the bias from one thread to another directly in this situation. Word biasedMark = prototypeMarkWord.or(thread); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), mark, biasedMark).equal(mark)) { + if (compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark)) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:transfer}", object); return; @@ -197,7 +198,7 @@ // that another thread raced us for the privilege of revoking the // bias of this particular object, so it's okay to continue in the // normal locking code. - Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord); + Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord, MARK_WORD_LOCATION); // Fall through to the normal CAS-based lock, because no matter what // the result of the above CAS, some thread must have succeeded in @@ -215,11 +216,11 @@ trace(trace, " unlockedMark: 0x%016lx\n", unlockedMark); // Copy this unlocked mark word into the lock slot on the stack - lock.writeWord(lockDisplacedMarkOffset(), unlockedMark); + lock.writeWord(lockDisplacedMarkOffset(), unlockedMark, DISPLACED_MARK_WORD_LOCATION); // Test if the object's mark word is unlocked, and if so, store the // (address of) the lock slot into the object's mark word. - Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock); + Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock, MARK_WORD_LOCATION); if (currentMark.notEqual(unlockedMark)) { trace(trace, " currentMark: 0x%016lx\n", currentMark); // The mark word in the object header was not the same. @@ -247,7 +248,7 @@ return; } else { // Recursively locked => write 0 to the lock slot - lock.writeWord(lockDisplacedMarkOffset(), Word.zero()); + lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION); traceObject(trace, "+lock{recursive}", object); } } else { @@ -302,7 +303,7 @@ final Word lock = CurrentLockNode.currentLock(); // Load displaced mark - final Word displacedMark = lock.readWord(lockDisplacedMarkOffset()); + final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION); trace(trace, " displacedMark: 0x%016lx\n", displacedMark); if (displacedMark.equal(0)) { @@ -313,7 +314,7 @@ // Test if object's mark word is pointing to the displaced mark word, and if so, restore // the displaced mark in the object - if the object's mark word is not pointing to // the displaced mark word, do unlocking via runtime call. - if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark).notEqual(lock)) { + if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock)) { // The object's mark word was not pointing to the displaced header, // we do unlocking via runtime call. probability(DEOPT_PATH_PROBABILITY); @@ -365,35 +366,37 @@ */ private static final boolean ENABLE_BREAKPOINT = false; + private static final Object MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter"); + @NodeIntrinsic(BreakpointNode.class) static native void bkpt(Object object, Word mark, Word tmp, Word value); private static void incCounter() { if (CHECK_BALANCED_MONITORS) { final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0); - counter.writeInt(0, count + 1); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION); } } private static void decCounter() { if (CHECK_BALANCED_MONITORS) { final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0); - counter.writeInt(0, count - 1); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION); } } @Snippet private static void initCounter() { final Word counter = MonitorCounterNode.counter(); - counter.writeInt(0, 0); + counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION); } @Snippet private static void checkCounter(String errMsg) { final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); if (count != 0) { vmError(errMsg, count); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Fri Mar 01 17:06:08 2013 +0100 @@ -29,8 +29,8 @@ import static com.oracle.graal.snippets.Snippet.Varargs.*; import static com.oracle.graal.snippets.SnippetTemplate.*; import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; +import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; import static com.oracle.graal.snippets.nodes.ExplodeLoopNode.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -62,13 +62,13 @@ @Snippet public static Word allocate(@Parameter("size") int size) { Word thread = thread(); - Word top = thread.readWord(threadTlabTopOffset()); - Word end = thread.readWord(threadTlabEndOffset()); + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); Word newTop = top.add(size); // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code) if (newTop.belowOrEqual(end)) { probability(FAST_PATH_PROBABILITY); - thread.writeWord(threadTlabTopOffset(), newTop); + writeTlabTop(thread, newTop); return top; } return Word.zero(); @@ -178,7 +178,7 @@ Word dims = DimensionsNode.allocaDimsArray(rank); ExplodeLoopNode.explodeLoop(); for (int i = 0; i < rank; i++) { - dims.writeInt(i * 4, dimensions[i]); + dims.writeInt(i * 4, dimensions[i], ANY_LOCATION); } return NewMultiArrayStubCall.call(hub, rank, dims); } @@ -194,20 +194,19 @@ * Formats some allocated memory with an object header zeroes out the rest. */ private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { - Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset()) : compileTimePrototypeMarkWord; - memory.writeWord(markOffset(), prototypeMarkWord); - memory.writeWord(hubOffset(), hub); + Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord; + initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { new_seqInit.inc(); explodeLoop(); for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } else { new_loopInit.inc(); for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } } @@ -217,13 +216,12 @@ * Formats some allocated memory with an object header zeroes out the rest. */ public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { - memory.writeWord(markOffset(), prototypeMarkWord); - memory.writeInt(arrayLengthOffset(), length); + memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION); // store hub last as the concurrent garbage collectors assume length is valid if hub field is not null - memory.writeWord(hubOffset(), hub); + initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { for (int offset = headerSize; offset < allocationSize; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -26,7 +26,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -34,7 +33,6 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; import com.oracle.graal.snippets.nodes.*; public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider { @@ -52,33 +50,30 @@ return arguments.get(0); } - private Method selectSnippetMethod(LoweringTool tool) { - ResolvedJavaType type = getObject().objectStamp().type(); - if (type.isArray()) { - return ObjectCloneSnippets.arrayCloneMethod; - } else if (type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { - // arrays are assignable to Object, Cloneable and Serializable - return ObjectCloneSnippets.genericCloneMethod; - } else { - return ObjectCloneSnippets.instanceCloneMethod; - } - } - @Override - public void lower(LoweringTool tool) { + protected StructuredGraph getSnippetGraph(LoweringTool tool) { if (!GraalOptions.IntrinsifyObjectClone) { - super.lower(tool); - return; - } - ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(selectSnippetMethod(tool)); - if (Debug.isLogEnabled()) { - Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType()); + return null; } + ResolvedJavaType type = getObject().objectStamp().type(); + Method method; + /* + * The first condition tests if the parameter is an array, the second condition tests if the + * parameter can be an array. Otherwise, the parameter is known to be a non-array object. + */ + if (type.isArray()) { + method = ObjectCloneSnippets.arrayCloneMethod; + } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { + method = ObjectCloneSnippets.genericCloneMethod; + } else { + method = ObjectCloneSnippets.instanceCloneMethod; + } + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method); StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); + assert snippetGraph != null : "ObjectCloneSnippets should be installed"; - InvokeNode invoke = replaceWithInvoke(); - InliningUtil.inline(invoke, snippetGraph, false); + return snippetGraph; } private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) { @@ -86,7 +81,7 @@ } private static ResolvedJavaType getConcreteType(ObjectStamp stamp, Assumptions assumptions) { - if (stamp.isExactType()) { + if (stamp.isExactType() || stamp.type() == null) { return stamp.type(); } else { ResolvedJavaType type = stamp.type().findUniqueConcreteSubtype(); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java Fri Mar 01 17:06:08 2013 +0100 @@ -53,12 +53,12 @@ private static Object instanceClone(Object src, Word hub, int layoutHelper) { int instanceSize = layoutHelper; Pointer memory = NewObjectSnippets.allocate(instanceSize); - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false); memory = Word.fromObject(result); for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset)); + memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); } return result; @@ -71,12 +71,12 @@ int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); Pointer memory = NewObjectSnippets.allocate(sizeInBytes); - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false); memory = Word.fromObject(result); for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset)); + memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); } return result; } @@ -94,14 +94,14 @@ public static Object instanceClone(Object src) { instanceCloneCounter.inc(); Word hub = getAndCheckHub(src); - return instanceClone(src, hub, hub.readInt(layoutHelperOffset())); + return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION)); } @Snippet public static Object arrayClone(Object src) { arrayCloneCounter.inc(); Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset()); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); return arrayClone(src, hub, layoutHelper); } @@ -109,7 +109,7 @@ public static Object genericClone(Object src) { genericCloneCounter.inc(); Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset()); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); if (layoutHelper < 0) { probability(LIKELY_PROBABILITY); genericArrayCloneCounter.inc(); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java Fri Mar 01 17:06:08 2013 +0100 @@ -25,8 +25,10 @@ import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.ClassSubstitution.*; +import com.oracle.graal.snippets.ClassSubstitution.MacroSubstitution; +import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; import com.oracle.graal.word.*; /** @@ -38,7 +40,7 @@ @MethodSubstitution(isStatic = false) public static Class getClass(final Object thisObj) { Word hub = loadHub(thisObj); - return unsafeCast(hub.readFinalObject(Word.signed(classMirrorOffset())), Class.class, true, true); + return unsafeCast(hub.readObject(Word.signed(classMirrorOffset()), LocationNode.FINAL_LOCATION), Class.class, true, true); } @MethodSubstitution(isStatic = false) diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java Fri Mar 01 17:06:08 2013 +0100 @@ -43,10 +43,10 @@ @MethodSubstitution(isStatic = false) private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) { Word rawThread = HotSpotCurrentRawThreadNode.get(); - Thread thread = (Thread) rawThread.readObject(threadObjectOffset()); + Thread thread = (Thread) rawThread.readObject(threadObjectOffset(), FINAL_LOCATION); if (thisObject == thread) { - Word osThread = rawThread.readWord(osThreadOffset()); - boolean interrupted = osThread.readInt(osThreadInterruptedOffset()) != 0; + Word osThread = rawThread.readWord(osThreadOffset(), FINAL_LOCATION); + boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), UNKNOWN_LOCATION) != 0; if (!interrupted || !clearInterrupted) { return interrupted; } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java Fri Mar 01 17:06:08 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.*; import com.oracle.graal.snippets.*; import com.oracle.graal.word.*; @@ -39,9 +40,11 @@ */ public class TypeCheckSnippetUtils { + public static final Object TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay"); + static boolean checkSecondarySubType(Word t, Word s) { // if (S.cache == T) return true - if (s.readWord(secondarySuperCacheOffset()).equal(t)) { + if (s.readWord(secondarySuperCacheOffset(), SECONDARY_SUPER_CACHE_LOCATION).equal(t)) { cacheHit.inc(); return true; } @@ -51,11 +54,11 @@ static boolean checkUnknownSubType(Word t, Word s) { // int off = T.offset - int superCheckOffset = t.readInt(superCheckOffsetOffset()); + int superCheckOffset = t.readInt(superCheckOffsetOffset(), FINAL_LOCATION); boolean primary = superCheckOffset != secondarySuperCacheOffset(); // if (T = S[off]) return true - if (s.readWord(superCheckOffset).equal(t)) { + if (s.readWord(superCheckOffset, TYPE_DISPLAY_LOCATION).equal(t)) { if (primary) { cacheHit.inc(); } else { @@ -81,12 +84,12 @@ } // if (S.scan_s_s_array(T)) { S.cache = T; return true; } - Word secondarySupers = s.readWord(secondarySupersOffset()); - int length = secondarySupers.readInt(metaspaceArrayLengthOffset()); + Word secondarySupers = s.readWord(secondarySupersOffset(), SECONDARY_SUPERS_LOCATION); + int length = secondarySupers.readInt(metaspaceArrayLengthOffset(), FINAL_LOCATION); for (int i = 0; i < length; i++) { - if (t.equal(loadWordElement(secondarySupers, i))) { + if (t.equal(loadSecondarySupersElement(secondarySupers, i))) { probability(NOT_LIKELY_PROBABILITY); - s.writeWord(secondarySuperCacheOffset(), t); + s.writeWord(secondarySuperCacheOffset(), t, SECONDARY_SUPER_CACHE_LOCATION); secondariesHit.inc(); return true; } @@ -103,8 +106,8 @@ return hintHubs; } - static Word loadWordElement(Word metaspaceArray, int index) { - return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize()); + static Word loadSecondarySupersElement(Word metaspaceArray, int index) { + return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize(), FINAL_LOCATION); } private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("TypeCheck") : null; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Fri Mar 01 17:06:08 2013 +0100 @@ -67,7 +67,7 @@ */ @Snippet private static Object newArray(@Parameter("hub") Word hub, @Parameter("length") int length, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { - int layoutHelper = hub.readInt(layoutHelperOffset()); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask(); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Fri Mar 01 17:06:08 2013 +0100 @@ -67,16 +67,15 @@ */ @Snippet private static Object newInstance(@Parameter("hub") Word hub, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { - int sizeInBytes = hub.readInt(klassInstanceSizeOffset()); + int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), FINAL_LOCATION); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { - if (hub.readInt(klassStateOffset()) == klassStateFullyInitialized()) { + if (hub.readInt(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) { Word memory = refillAllocate(intArrayHub, sizeInBytes, log); if (memory.notEqual(0)) { - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); - memory.writeWord(markOffset(), prototypeMarkWord); - memory.writeWord(hubOffset(), hub); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); + initializeObjectHeader(memory, prototypeMarkWord, hub); for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } return verifyOop(memory.toObject()); } @@ -100,8 +99,8 @@ int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords() * wordSize(); Word thread = thread(); - Word top = thread.readWord(threadTlabTopOffset()); - Word end = thread.readWord(threadTlabEndOffset()); + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); // calculate amount of free space Word tlabFreeSpaceInBytes = end.subtract(top); @@ -115,16 +114,16 @@ // Retain TLAB and allocate object in shared space if // the amount free in the TLAB is too large to discard. - Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset()); + Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset(), TLAB_REFILL_WASTE_LIMIT_LOCATION); if (tlabFreeSpaceInWords.belowOrEqual(refillWasteLimit)) { if (tlabStats()) { // increment number of refills - thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset()) + 1); - log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset())); + thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION); + log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION)); // accumulate wastage - Word wastage = thread.readWord(tlabFastRefillWasteOffset()).add(tlabFreeSpaceInWords); + Word wastage = thread.readWord(tlabFastRefillWasteOffset(), TLAB_FAST_REFILL_WASTE_LOCATION).add(tlabFreeSpaceInWords); log(log, "thread: %p -- accumulated wastage %d\n", thread, wastage); - thread.writeWord(tlabFastRefillWasteOffset(), wastage); + thread.writeWord(tlabFastRefillWasteOffset(), wastage, TLAB_FAST_REFILL_WASTE_LOCATION); } // if TLAB is currently allocated (top or end != null) then @@ -137,22 +136,19 @@ int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts; NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false); - Word allocated = thread.readWord(threadAllocatedBytesOffset()); - allocated = allocated.add(top.subtract(thread.readWord(threadTlabStartOffset()))); - thread.writeWord(threadAllocatedBytesOffset(), allocated); + Word allocated = thread.readWord(threadAllocatedBytesOffset(), TLAB_THREAD_ALLOCATED_BYTES_LOCATION); + allocated = allocated.add(top.subtract(readTlabStart(thread))); + thread.writeWord(threadAllocatedBytesOffset(), allocated, TLAB_THREAD_ALLOCATED_BYTES_LOCATION); } // refill the TLAB with an eden allocation - Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset()); + Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset(), TLAB_SIZE_LOCATION); Word tlabRefillSizeInBytes = tlabRefillSizeInWords.multiply(wordSize()); // allocate new TLAB, address returned in top top = edenAllocate(tlabRefillSizeInBytes, log); if (top.notEqual(0)) { - thread.writeWord(threadTlabStartOffset(), top); - thread.writeWord(threadTlabTopOffset(), top); - end = top.add(tlabRefillSizeInBytes.subtract(alignmentReserveInBytes)); - thread.writeWord(threadTlabEndOffset(), end); + initializeTlab(thread, top, end); return allocate(sizeInBytes); } else { @@ -161,11 +157,11 @@ } else { // Retain TLAB Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement()); - thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit); + thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION); log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit); if (tlabStats()) { - thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset()) + 1); + thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset(), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1, TLAB_SLOW_ALLOCATIONS_LOCATION); } return edenAllocate(Word.unsigned(sizeInBytes), log); @@ -184,18 +180,18 @@ Word heapEndAddress = Word.unsigned(heapEndAddress()); while (true) { - Word heapTop = heapTopAddress.readWord(0); + Word heapTop = heapTopAddress.readWord(0, HEAP_TOP_LOCATION); Word newHeapTop = heapTop.add(sizeInBytes); if (newHeapTop.belowOrEqual(heapTop)) { return Word.zero(); } - Word heapEnd = heapEndAddress.readWord(0); + Word heapEnd = heapEndAddress.readWord(0, HEAP_END_LOCATION); if (newHeapTop.aboveThan(heapEnd)) { return Word.zero(); } - if (compareAndSwap(heapTopAddress, 0, heapTop, newHeapTop).equal(heapTop)) { + if (compareAndSwap(heapTopAddress, 0, heapTop, newHeapTop, HEAP_TOP_LOCATION).equal(heapTop)) { return heapTop; } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Fri Mar 01 17:06:08 2013 +0100 @@ -203,16 +203,16 @@ } private void propagateDelete(FloatingNode node) { - assert node instanceof PhiNode || node instanceof ValueProxyNode; + assert node instanceof PhiNode || node instanceof ProxyNode; if (node.isDeleted()) { return; } // Collect all phi functions that use this phi so that we can delete them recursively (after // we delete ourselves to avoid circles). - List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ValueProxyNode.class)).snapshot(); + List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ProxyNode.class)).snapshot(); // Remove the phi function from all FrameStates where it is used and then delete it. - assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; node.replaceAtUsages(null); node.safeDelete(); @@ -235,21 +235,21 @@ ValueNode value = localAt(i); if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - storeLocal(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value))); + storeLocal(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value))); } } for (int i = 0; i < stackSize(); i++) { ValueNode value = stackAt(i); if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - storeStack(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value))); + storeStack(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value))); } } for (int i = 0; i < locks.length; i++) { ValueNode value = locks[i]; if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - locks[i] = graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value)); + locks[i] = graph.unique(new ProxyNode(value, loopExit, PhiType.Value)); } } } @@ -259,21 +259,21 @@ ValueNode value = localAt(i); if (value != null) { Debug.log(" inserting proxy for %s", value); - storeLocal(i, graph.unique(new ValueProxyNode(value, begin, PhiType.Value))); + storeLocal(i, graph.unique(new ProxyNode(value, begin, PhiType.Value))); } } for (int i = 0; i < stackSize(); i++) { ValueNode value = stackAt(i); if (value != null) { Debug.log(" inserting proxy for %s", value); - storeStack(i, graph.unique(new ValueProxyNode(value, begin, PhiType.Value))); + storeStack(i, graph.unique(new ProxyNode(value, begin, PhiType.Value))); } } for (int i = 0; i < locks.length; i++) { ValueNode value = locks[i]; if (value != null) { Debug.log(" inserting proxy for %s", value); - locks[i] = graph.unique(new ValueProxyNode(value, begin, PhiType.Value)); + locks[i] = graph.unique(new ProxyNode(value, begin, PhiType.Value)); } } } @@ -292,7 +292,7 @@ public void cleanupDeletedPhis() { for (int i = 0; i < localsSize(); i++) { if (localAt(i) != null && localAt(i).isDeleted()) { - assert localAt(i) instanceof PhiNode || localAt(i) instanceof ValueProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i); + assert localAt(i) instanceof PhiNode || localAt(i) instanceof ProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i); storeLocal(i, null); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Fri Mar 01 17:06:08 2013 +0100 @@ -23,21 +23,16 @@ package com.oracle.graal.java; import com.oracle.graal.api.meta.*; -import com.oracle.graal.phases.*; public class GraphBuilderConfiguration { - public static enum ResolvePolicy { - Default, EagerForSnippets, Eager, - } - - private final ResolvePolicy resolving; - private final PhasePlan plan; + private final boolean eagerResolving; + private final boolean omitAllExceptionEdges; private ResolvedJavaType[] skippedExceptionTypes; - public GraphBuilderConfiguration(ResolvePolicy resolving, PhasePlan plan) { - this.resolving = resolving; - this.plan = plan; + protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges) { + this.eagerResolving = eagerResolving; + this.omitAllExceptionEdges = omitAllExceptionEdges; } public void setSkippedExceptionTypes(ResolvedJavaType[] skippedExceptionTypes) { @@ -48,31 +43,23 @@ return skippedExceptionTypes; } - public boolean eagerResolvingForSnippets() { - return (resolving == ResolvePolicy.EagerForSnippets || resolving == ResolvePolicy.Eager); + public boolean eagerResolving() { + return eagerResolving; } - public boolean eagerResolving() { - return (resolving == ResolvePolicy.Eager); - } - - public PhasePlan plan() { - return plan; + public boolean omitAllExceptionEdges() { + return omitAllExceptionEdges; } public static GraphBuilderConfiguration getDefault() { - return getDefault(null); + return new GraphBuilderConfiguration(false, false); } - public static GraphBuilderConfiguration getDefault(PhasePlan plan) { - return new GraphBuilderConfiguration(ResolvePolicy.Default, plan); + public static GraphBuilderConfiguration getEagerDefault() { + return new GraphBuilderConfiguration(true, false); } public static GraphBuilderConfiguration getSnippetDefault() { - return getSnippetDefault(null); - } - - public static GraphBuilderConfiguration getSnippetDefault(PhasePlan plan) { - return new GraphBuilderConfiguration(ResolvePolicy.EagerForSnippets, plan); + return new GraphBuilderConfiguration(true, true); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -182,11 +182,12 @@ currentBlock = blockMap.startBlock; blockMap.startBlock.entryState = frameState; if (blockMap.startBlock.isLoopHeader) { - // TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it - // expects currentBlock, - // etc. to be set up correctly. A better solution to this problem of start blocks that - // are loop headers - // would be to create a dummy block in BciBlockMapping. + /* + * TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it + * expects currentBlock, etc. to be set up correctly. A better solution to this problem + * of start blocks that are loop headers would be to create a dummy block in + * BciBlockMapping. + */ appendGoto(createTarget(blockMap.startBlock, frameState)); } else { blockMap.startBlock.firstInstruction = lastInstr; @@ -635,21 +636,21 @@ private JavaType lookupType(int cpi, int bytecode) { eagerResolvingForSnippets(cpi, bytecode); JavaType result = constantPool.lookupType(cpi, bytecode); - assert !graphBuilderConfig.eagerResolvingForSnippets() || result instanceof ResolvedJavaType; + assert !graphBuilderConfig.eagerResolving() || result instanceof ResolvedJavaType; return result; } private JavaMethod lookupMethod(int cpi, int opcode) { eagerResolvingForSnippets(cpi, opcode); JavaMethod result = constantPool.lookupMethod(cpi, opcode); - assert !graphBuilderConfig.eagerResolvingForSnippets() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result; + assert !graphBuilderConfig.eagerResolving() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result; return result; } private JavaField lookupField(int cpi, int opcode) { eagerResolvingForSnippets(cpi, opcode); JavaField result = constantPool.lookupField(cpi, opcode); - assert !graphBuilderConfig.eagerResolvingForSnippets() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; + assert !graphBuilderConfig.eagerResolving() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; return result; } @@ -660,14 +661,8 @@ return result; } - // private void eagerResolving(int cpi, int bytecode) { - // if (graphBuilderConfig.eagerResolving()) { - // constantPool.loadReferencedType(cpi, bytecode); - // } - // } - private void eagerResolvingForSnippets(int cpi, int bytecode) { - if (graphBuilderConfig.eagerResolvingForSnippets()) { + if (graphBuilderConfig.eagerResolving()) { constantPool.loadReferencedType(cpi, bytecode); } } @@ -1038,13 +1033,13 @@ } JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass()); - if (graphBuilderConfig.eagerResolvingForSnippets()) { + if (graphBuilderConfig.eagerResolving()) { returnType = returnType.resolve(targetMethod.getDeclaringClass()); } MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType)); // be conservative if information was not recorded (could result in endless recompiles // otherwise) - if (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE) { + if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE)) { ValueNode result = appendWithBCI(currentGraph.add(new InvokeNode(callTarget, bci()))); frameState.pushReturn(resultType, result); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Fri Mar 01 17:06:08 2013 +0100 @@ -26,10 +26,11 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 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.ConditionFlag; import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; @@ -48,12 +49,12 @@ MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L; - public static class Op1Reg extends AMD64LIRInstruction { + public static class Unary2Op extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG}) protected Value x; + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; - public Op1Reg(AMD64Arithmetic opcode, Value result, Value x) { + public Unary2Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) { this.opcode = opcode; this.result = result; this.x = x; @@ -65,12 +66,12 @@ } } - public static class Op1Stack extends AMD64LIRInstruction { + public static class Unary1Op extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG, STACK, CONST}) protected Value x; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; - public Op1Stack(AMD64Arithmetic opcode, Value result, Value x) { + public Unary1Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) { this.opcode = opcode; this.result = result; this.x = x; @@ -264,14 +265,12 @@ @SuppressWarnings("unused") - protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, Value result) { + protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, AllocatableValue result) { switch (opcode) { case INEG: masm.negl(asIntReg(result)); break; case LNEG: masm.negq(asLongReg(result)); break; case L2I: masm.andl(asIntReg(result), 0xFFFFFFFF); break; - case I2B: masm.signExtendByte(asIntReg(result)); break; case I2C: masm.andl(asIntReg(result), 0xFFFF); break; - case I2S: masm.signExtendShort(asIntReg(result)); break; default: throw GraalInternalError.shouldNotReachHere(); } } @@ -286,9 +285,9 @@ 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: masm.shll(asIntReg(dst)); break; - case ISHR: masm.sarl(asIntReg(dst)); break; - case IUSHR:masm.shrl(asIntReg(dst)); break; + case ISHL: assert asIntReg(src) == AMD64.rcx; masm.shll(asIntReg(dst)); break; + case ISHR: assert asIntReg(src) == AMD64.rcx; masm.sarl(asIntReg(dst)); break; + case IUSHR: assert asIntReg(src) == AMD64.rcx; masm.shrl(asIntReg(dst)); break; case LADD: masm.addq(asLongReg(dst), asLongReg(src)); break; case LSUB: masm.subq(asLongReg(dst), asLongReg(src)); break; @@ -296,9 +295,9 @@ 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: masm.shlq(asLongReg(dst)); break; - case LSHR: masm.sarq(asLongReg(dst)); break; - case LUSHR:masm.shrq(asLongReg(dst)); break; + case LSHL: assert asIntReg(src) == AMD64.rcx; masm.shlq(asLongReg(dst)); break; + case LSHR: assert asIntReg(src) == AMD64.rcx; masm.sarq(asLongReg(dst)); break; + case LUSHR: assert asIntReg(src) == AMD64.rcx; masm.shrq(asLongReg(dst)); break; case FADD: masm.addss(asFloatReg(dst), asFloatReg(src)); break; case FSUB: masm.subss(asFloatReg(dst), asFloatReg(src)); break; @@ -316,6 +315,8 @@ case DOR: masm.orpd(asDoubleReg(dst), asDoubleReg(src)); break; case DXOR: masm.xorpd(asDoubleReg(dst), asDoubleReg(src)); break; + case I2B: masm.movsxb(asIntReg(dst), asIntReg(src)); break; + case I2S: masm.movsxw(asIntReg(dst), asIntReg(src)); break; case I2L: masm.movslq(asLongReg(dst), asIntReg(src)); break; case F2D: masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src)); break; case D2F: masm.cvtsd2ss(asFloatReg(dst), asDoubleReg(src)); break; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java Fri Mar 01 17:06:08 2013 +0100 @@ -24,7 +24,6 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.asm.*; @@ -35,10 +34,10 @@ } @Opcode private final IntrinsicOpcode opcode; - @Def protected Value result; - @Use({OperandFlag.REG, OperandFlag.ADDR}) protected Value input; + @Def protected AllocatableValue result; + @Use({OperandFlag.REG, OperandFlag.STACK}) protected AllocatableValue input; - public AMD64BitManipulationOp(IntrinsicOpcode opcode, Value result, Value input) { + public AMD64BitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input) { this.opcode = opcode; this.result = result; this.input = input; @@ -47,8 +46,8 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { Register dst = ValueUtil.asIntReg(result); - if (ValueUtil.isAddress(input)) { - AMD64Address src = (AMD64Address) ValueUtil.asAddress(input); + if (ValueUtil.isRegister(input)) { + Register src = ValueUtil.asRegister(input); switch (opcode) { case IPOPCNT: masm.popcntl(dst, src); @@ -67,7 +66,7 @@ break; } } else { - Register src = ValueUtil.asRegister(input); + AMD64Address src = (AMD64Address) tasm.asAddress(input); switch (opcode) { case IPOPCNT: masm.popcntl(dst, src); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Fri Mar 01 17:06:08 2013 +0100 @@ -24,6 +24,7 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + import static java.lang.Double.*; import static java.lang.Float.*; @@ -42,6 +43,7 @@ @Opcode("MOVE") public static class SpillMoveOp extends AMD64LIRInstruction implements MoveOp { + @Def({REG, STACK}) protected Value result; @Use({REG, STACK, CONST}) protected Value input; @@ -59,15 +61,16 @@ public Value getInput() { return input; } + @Override public Value getResult() { return result; } } - @Opcode("MOVE") public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp { + @Def({REG, HINT}) protected Value result; @Use({REG, STACK, CONST}) protected Value input; @@ -85,15 +88,16 @@ public Value getInput() { return input; } + @Override public Value getResult() { return result; } } - @Opcode("MOVE") public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp { + @Def({REG, STACK}) protected Value result; @Use({REG, CONST, HINT}) protected Value input; @@ -111,66 +115,201 @@ public Value getInput() { return input; } + @Override public Value getResult() { return result; } } + public abstract static class MemOp extends AMD64LIRInstruction { - public static class LoadOp extends AMD64LIRInstruction { - @Def({REG}) protected Value result; - @Use({ADDR}) protected Value address; + @Use({ADDR}) protected AMD64Address address; @State protected LIRFrameState state; - public LoadOp(Value result, Value address, LIRFrameState state) { - this.result = result; + public MemOp(AMD64Address address, LIRFrameState state) { this.address = address; this.state = state; } + protected abstract void emitMemAccess(AMD64MacroAssembler masm); + @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - load(tasm, masm, result, (AMD64Address) address, state); + if (state != null) { + tasm.recordImplicitException(masm.codeBuffer.position(), state); + } + emitMemAccess(masm); + } + } + + public static class LoadOp extends MemOp { + + @Def({REG}) protected AllocatableValue result; + + public LoadOp(AllocatableValue result, AMD64Address address, LIRFrameState state) { + super(address, state); + this.result = result; + } + + @Override + public void emitMemAccess(AMD64MacroAssembler masm) { + switch (address.getKind()) { + case Boolean: + case Byte: + masm.movsxb(asRegister(result), address); + break; + case Char: + masm.movzxl(asRegister(result), address); + break; + case Short: + masm.movswl(asRegister(result), address); + break; + case Int: + masm.movslq(asRegister(result), address); + break; + case Long: + masm.movq(asRegister(result), address); + break; + case Float: + masm.movflt(asFloatReg(result), address); + break; + case Double: + masm.movdbl(asDoubleReg(result), address); + break; + case Object: + masm.movq(asRegister(result), address); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } } } + public static class StoreOp extends MemOp { - public static class StoreOp extends AMD64LIRInstruction { - @Use({ADDR}) protected Value address; - @Use({REG, CONST}) protected Value input; - @State protected LIRFrameState state; + @Use({REG}) protected AllocatableValue input; - public StoreOp(Value address, Value input, LIRFrameState state) { - this.address = address; + public StoreOp(AMD64Address address, AllocatableValue input, LIRFrameState state) { + super(address, state); this.input = input; - this.state = state; } @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - store(tasm, masm, (AMD64Address) address, input, state); + public void emitMemAccess(AMD64MacroAssembler masm) { + assert isRegister(input); + switch (address.getKind()) { + case Boolean: + case Byte: + masm.movb(address, asRegister(input)); + break; + case Char: + case Short: + masm.movw(address, asRegister(input)); + break; + case Int: + masm.movl(address, asRegister(input)); + break; + case Long: + masm.movq(address, asRegister(input)); + break; + case Float: + masm.movflt(address, asFloatReg(input)); + break; + case Double: + masm.movsd(address, asDoubleReg(input)); + break; + case Object: + masm.movq(address, asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } } } + public static class StoreConstantOp extends MemOp { + + @Use({CONST}) protected Constant input; + + public StoreConstantOp(AMD64Address address, Constant input, LIRFrameState state) { + super(address, state); + this.input = input; + } + + @Override + public void emitMemAccess(AMD64MacroAssembler masm) { + switch (address.getKind()) { + case Boolean: + case Byte: + masm.movb(address, input.asInt() & 0xFF); + break; + case Char: + case Short: + masm.movw(address, input.asInt() & 0xFFFF); + break; + case Int: + masm.movl(address, input.asInt()); + break; + case Long: + if (NumUtil.isInt(input.asLong())) { + masm.movslq(address, (int) input.asLong()); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + break; + case Float: + masm.movl(address, floatToRawIntBits(input.asFloat())); + break; + case Double: + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + case Object: + if (input.isNull()) { + masm.movptr(address, 0); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } public static class LeaOp extends AMD64LIRInstruction { - @Def({REG}) protected Value result; - @Use({ADDR, STACK, UNINITIALIZED}) protected Value address; - public LeaOp(Value result, Value address) { + @Def({REG}) protected AllocatableValue result; + @Use({ADDR, UNINITIALIZED}) protected AMD64Address address; + + public LeaOp(AllocatableValue result, AMD64Address address) { this.result = result; this.address = address; } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.leaq(asLongReg(result), (AMD64Address) tasm.asAddress(address)); + masm.leaq(asLongReg(result), address); } } + public static class StackLeaOp extends AMD64LIRInstruction { + + @Def({REG}) protected AllocatableValue result; + @Use({STACK, UNINITIALIZED}) protected StackSlot slot; + + public StackLeaOp(AllocatableValue result, StackSlot slot) { + this.result = result; + this.slot = slot; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + masm.leaq(asLongReg(result), (AMD64Address) tasm.asAddress(slot)); + } + } public static class MembarOp extends AMD64LIRInstruction { + private final int barriers; public MembarOp(final int barriers) { @@ -183,9 +322,9 @@ } } + public static class NullCheckOp extends AMD64LIRInstruction { - public static class NullCheckOp extends AMD64LIRInstruction { - @Use protected Value input; + @Use protected AllocatableValue input; @State protected LIRFrameState state; public NullCheckOp(Variable input, LIRFrameState state) { @@ -200,15 +339,15 @@ } } - @Opcode("CAS") public static class CompareAndSwapOp extends AMD64LIRInstruction { - @Def protected Value result; - @Use({ADDR}) protected Value address; - @Use protected Value cmpValue; - @Use protected Value newValue; - public CompareAndSwapOp(Value result, Address address, Value cmpValue, Value newValue) { + @Def protected AllocatableValue result; + @Use({ADDR}) protected AMD64Address address; + @Use protected AllocatableValue cmpValue; + @Use protected AllocatableValue newValue; + + public CompareAndSwapOp(AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) { this.result = result; this.address = address; this.cmpValue = cmpValue; @@ -217,11 +356,10 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - compareAndSwap(tasm, masm, result, (AMD64Address) address, cmpValue, newValue); + compareAndSwap(tasm, masm, result, address, cmpValue, newValue); } } - public static void move(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) { if (isRegister(input)) { if (isRegister(result)) { @@ -255,43 +393,79 @@ return; } switch (input.getKind()) { - case Int: masm.movl(asRegister(result), asRegister(input)); break; - case Long: masm.movq(asRegister(result), asRegister(input)); break; - case Float: masm.movflt(asFloatReg(result), asFloatReg(input)); break; - case Double: masm.movdbl(asDoubleReg(result), asDoubleReg(input)); break; - case Object: masm.movq(asRegister(result), asRegister(input)); break; - default: throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind()); + case Int: + masm.movl(asRegister(result), asRegister(input)); + break; + case Long: + masm.movq(asRegister(result), asRegister(input)); + break; + case Float: + masm.movflt(asFloatReg(result), asFloatReg(input)); + break; + case Double: + masm.movdbl(asDoubleReg(result), asDoubleReg(input)); + break; + case Object: + masm.movq(asRegister(result), asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind()); } } private static void reg2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) { AMD64Address dest = (AMD64Address) tasm.asAddress(result); switch (input.getKind()) { - case Int: masm.movl(dest, asRegister(input)); break; - case Long: masm.movq(dest, asRegister(input)); break; - case Float: masm.movflt(dest, asFloatReg(input)); break; - case Double: masm.movsd(dest, asDoubleReg(input)); break; - case Object: masm.movq(dest, asRegister(input)); break; - default: throw GraalInternalError.shouldNotReachHere(); + case Int: + masm.movl(dest, asRegister(input)); + break; + case Long: + masm.movq(dest, asRegister(input)); + break; + case Float: + masm.movflt(dest, asFloatReg(input)); + break; + case Double: + masm.movsd(dest, asDoubleReg(input)); + break; + case Object: + masm.movq(dest, asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } } private static void stack2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) { AMD64Address src = (AMD64Address) tasm.asAddress(input); switch (input.getKind()) { - case Int: masm.movl(asRegister(result), src); break; - case Long: masm.movq(asRegister(result), src); break; - case Float: masm.movflt(asFloatReg(result), src); break; - case Double: masm.movdbl(asDoubleReg(result), src); break; - case Object: masm.movq(asRegister(result), src); break; - default: throw GraalInternalError.shouldNotReachHere(); + case Int: + masm.movl(asRegister(result), src); + break; + case Long: + masm.movq(asRegister(result), src); + break; + case Float: + masm.movflt(asFloatReg(result), src); + break; + case Double: + masm.movdbl(asDoubleReg(result), src); + break; + case Object: + masm.movq(asRegister(result), src); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } } private static void const2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Constant input) { - // Note: we use the kind of the input operand (and not the kind of the result operand) because they don't match - // in all cases. For example, an object constant can be loaded to a long register when unsafe casts occurred (e.g., - // for a write barrier where arithmetic operations are then performed on the pointer). + /* + * Note: we use the kind of the input operand (and not the kind of the result operand) + * because they don't match in all cases. For example, an object constant can be loaded to a + * long register when unsafe casts occurred (e.g., for a write barrier where arithmetic + * operations are then performed on the pointer). + */ switch (input.getKind().getStackKind()) { case Int: if (tasm.runtime.needsDataPatch(input)) { @@ -352,10 +526,18 @@ assert !tasm.runtime.needsDataPatch(input); AMD64Address dest = (AMD64Address) tasm.asAddress(result); switch (input.getKind().getStackKind()) { - case Int: masm.movl(dest, input.asInt()); break; - case Long: masm.movlong(dest, input.asLong()); break; - case Float: masm.movl(dest, floatToRawIntBits(input.asFloat())); break; - case Double: masm.movlong(dest, doubleToRawLongBits(input.asDouble())); break; + case Int: + masm.movl(dest, input.asInt()); + break; + case Long: + masm.movlong(dest, input.asLong()); + break; + case Float: + masm.movl(dest, floatToRawIntBits(input.asFloat())); + break; + case Double: + masm.movlong(dest, doubleToRawLongBits(input.asDouble())); + break; case Object: if (input.isNull()) { masm.movlong(dest, 0L); @@ -368,87 +550,22 @@ } } - - public static void load(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, AMD64Address loadAddr, LIRFrameState info) { - if (info != null) { - tasm.recordImplicitException(masm.codeBuffer.position(), info); - } - switch (loadAddr.getKind()) { - case Boolean: - case Byte: masm.movsxb(asRegister(result), loadAddr); break; - case Char: masm.movzxl(asRegister(result), loadAddr); break; - case Short: masm.movswl(asRegister(result), loadAddr); break; - case Int: masm.movslq(asRegister(result), loadAddr); break; - case Long: masm.movq(asRegister(result), loadAddr); break; - case Float: masm.movflt(asFloatReg(result), loadAddr); break; - case Double: masm.movdbl(asDoubleReg(result), loadAddr); break; - case Object: masm.movq(asRegister(result), loadAddr); break; - default: throw GraalInternalError.shouldNotReachHere(); - } - } - - public static void store(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Address storeAddr, Value input, LIRFrameState info) { - if (info != null) { - tasm.recordImplicitException(masm.codeBuffer.position(), info); - } - - if (isRegister(input)) { - switch (storeAddr.getKind()) { - case Boolean: - case Byte: masm.movb(storeAddr, asRegister(input)); break; - case Char: - case Short: masm.movw(storeAddr, asRegister(input)); break; - case Int: masm.movl(storeAddr, asRegister(input)); break; - case Long: masm.movq(storeAddr, asRegister(input)); break; - case Float: masm.movflt(storeAddr, asFloatReg(input)); break; - case Double: masm.movsd(storeAddr, asDoubleReg(input)); break; - case Object: masm.movq(storeAddr, asRegister(input)); break; - default: throw GraalInternalError.shouldNotReachHere(); - } - } else if (isConstant(input)) { - Constant c = (Constant) input; - switch (storeAddr.getKind()) { - case Boolean: - case Byte: masm.movb(storeAddr, c.asInt() & 0xFF); break; - case Char: - case Short: masm.movw(storeAddr, c.asInt() & 0xFFFF); break; - case Int: masm.movl(storeAddr, c.asInt()); break; - case Long: - if (NumUtil.isInt(c.asLong())) { - masm.movslq(storeAddr, (int) c.asLong()); - } else { - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - case Float: masm.movl(storeAddr, floatToRawIntBits(c.asFloat())); break; - case Double: throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - case Object: - if (c.isNull()) { - masm.movptr(storeAddr, 0); - } else { - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - - protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, AMD64Address address, Value cmpValue, Value newValue) { + protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) { assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax; if (tasm.target.isMP) { masm.lock(); } switch (cmpValue.getKind()) { - case Int: masm.cmpxchgl(asRegister(newValue), address); break; + case Int: + masm.cmpxchgl(asRegister(newValue), address); + break; case Long: - case Object: masm.cmpxchgq(asRegister(newValue), address); break; - default: throw GraalInternalError.shouldNotReachHere(); + case Object: + masm.cmpxchgq(asRegister(newValue), address); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Fri Mar 01 17:06:08 2013 +0100 @@ -120,11 +120,11 @@ public static class LoadOp extends PTXLIRInstruction { - @Def({REG}) protected Value result; - @Use({ADDR}) protected Value address; + @Def({REG}) protected AllocatableValue result; + @Use({ADDR}) protected PTXAddress address; @State protected LIRFrameState state; - public LoadOp(Value result, Value address, LIRFrameState state) { + public LoadOp(AllocatableValue result, PTXAddress address, LIRFrameState state) { this.result = result; this.address = address; this.state = state; @@ -132,17 +132,28 @@ @Override public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { - load(tasm, masm, result, (PTXAddress) address, state); + Register a = asRegister(address.getBase()); + long immOff = address.getDisplacement(); + switch (address.getKind()) { + case Int: + masm.ld_global_s32(asRegister(result), a, immOff); + break; + case Object: + masm.ld_global_u32(asRegister(result), a, immOff); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } } } public static class StoreOp extends PTXLIRInstruction { - @Use({ADDR}) protected Value address; - @Use({REG, CONST}) protected Value input; + @Use({ADDR}) protected PTXAddress address; + @Use({REG}) protected AllocatableValue input; @State protected LIRFrameState state; - public StoreOp(Value address, Value input, LIRFrameState state) { + public StoreOp(PTXAddress address, AllocatableValue input, LIRFrameState state) { this.address = address; this.input = input; this.state = state; @@ -150,16 +161,26 @@ @Override public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { - store(tasm, masm, (PTXAddress) address, input, state); + Register a = asRegister(address.getBase()); + long immOff = address.getDisplacement(); + + assert isRegister(input); + switch (address.getKind()) { + case Int: + masm.st_global_s32(a, immOff, asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } } } public static class LeaOp extends PTXLIRInstruction { - @Def({REG}) protected Value result; - @Use({ADDR, STACK, UNINITIALIZED}) protected Value address; + @Def({REG}) protected AllocatableValue result; + @Use({ADDR, UNINITIALIZED}) protected PTXAddress address; - public LeaOp(Value result, Value address) { + public LeaOp(AllocatableValue result, PTXAddress address) { this.result = result; this.address = address; } @@ -170,15 +191,31 @@ } } + public static class StackLeaOp extends PTXLIRInstruction { + + @Def({REG}) protected AllocatableValue result; + @Use({STACK, UNINITIALIZED}) protected StackSlot slot; + + public StackLeaOp(AllocatableValue result, StackSlot slot) { + this.result = result; + this.slot = slot; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + throw new InternalError("NYI"); + } + } + @Opcode("CAS") public static class CompareAndSwapOp extends PTXLIRInstruction { - @Def protected Value result; - @Use({ADDR}) protected Value address; - @Use protected Value cmpValue; - @Use protected Value newValue; + @Def protected AllocatableValue result; + @Use({ADDR}) protected PTXAddress address; + @Use protected AllocatableValue cmpValue; + @Use protected AllocatableValue newValue; - public CompareAndSwapOp(Value result, Address address, Value cmpValue, Value newValue) { + public CompareAndSwapOp(AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) { this.result = result; this.address = address; this.cmpValue = cmpValue; @@ -187,7 +224,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { - compareAndSwap(tasm, masm, result, (Address) address, cmpValue, newValue); + compareAndSwap(tasm, masm, result, address, cmpValue, newValue); } } @@ -239,47 +276,7 @@ } @SuppressWarnings("unused") - public static void load(TargetMethodAssembler tasm, PTXAssembler masm, Value result, PTXAddress loadAddr, LIRFrameState info) { - Register a = asRegister(loadAddr.getBase()); - long immOff = loadAddr.getDisplacement(); - switch (loadAddr.getKind()) { - case Int: - masm.ld_global_s32(asRegister(result), a, immOff); - break; - case Object: - masm.ld_global_u32(asRegister(result), a, immOff); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - @SuppressWarnings("unused") - public static void store(TargetMethodAssembler tasm, PTXAssembler masm, PTXAddress storeAddr, Value input, LIRFrameState info) { - Register a = asRegister(storeAddr.getBase()); - long immOff = storeAddr.getDisplacement(); - if (isRegister(input)) { - switch (storeAddr.getKind()) { - case Int: - masm.st_global_s32(a, immOff, asRegister(input)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } else if (isConstant(input)) { - Constant c = (Constant) input; - switch (storeAddr.getKind()) { - default: - throw GraalInternalError.shouldNotReachHere(); - } - - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - - @SuppressWarnings("unused") - protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, Value result, Address address, Value cmpValue, Value newValue) { + protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) { throw new InternalError("NYI"); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Fri Mar 01 17:06:08 2013 +0100 @@ -347,28 +347,4 @@ } } } - - /** - * Clears the specified location as a reference in the reference map of the debug information. - * The tracked location can be a {@link RegisterValue} or a {@link StackSlot}. Note that a - * {@link Constant} is automatically tracked. - * - * @param location The location to be removed from the reference map. - * @param registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}. - * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}. - */ - public void clearReference(Value location, BitSet registerRefMap, BitSet frameRefMap) { - if (location.getKind() == Kind.Object) { - if (location instanceof RegisterValue) { - registerRefMap.clear(asRegister(location).number); - } else if (isStackSlot(location)) { - int index = frameRefMapIndex(asStackSlot(location)); - if (index < frameRefMap.size()) { - frameRefMap.clear(index); - } - } else { - assert isConstant(location); - } - } - } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Fri Mar 01 17:06:08 2013 +0100 @@ -181,6 +181,11 @@ ILLEGAL, /** + * The value can be {@link AllocatableValue#UNUSED}. + */ + UNUSED, + + /** * The register allocator should try to assign a certain register to improve code quality. * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints. */ diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Fri Mar 01 17:06:08 2013 +0100 @@ -232,7 +232,8 @@ private static Value allowed(Object op, Value value, OperandMode mode, EnumSet flags) { if ((isVariable(value) && flags.contains(OperandFlag.REG)) || (isRegister(value) && flags.contains(OperandFlag.REG)) || (isStackSlot(value) && flags.contains(OperandFlag.STACK)) || - (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) { + (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL)) || + (value == AllocatableValue.UNUSED && flags.contains(OperandFlag.UNUSED))) { return value; } TTY.println("instruction %s", op); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Fri Mar 01 17:06:08 2013 +0100 @@ -33,8 +33,6 @@ */ public class StandardOp { - private static Value[] EMPTY = new Value[0]; - /** * Marker interface for LIR ops that can fall through to the next operation, like a switch * statement. setFallThroughTarget(null) can be used to make the operation fall through to the @@ -99,24 +97,6 @@ } } - public static class PhiJumpOp extends JumpOp { - - @Alive({REG, STACK, CONST}) protected Value[] phiInputs; - - public PhiJumpOp(LabelRef destination, Value[] phiInputs) { - super(destination, null); - this.phiInputs = phiInputs; - } - - public void markResolved() { - phiInputs = EMPTY; - } - - public Value[] getPhiInputs() { - return phiInputs; - } - } - /** * Marker interface for a LIR operation that is a conditional jump to {@link #destination()}. * Conditional jumps may be negated or optimized away after register allocation. diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java Fri Mar 01 17:06:08 2013 +0100 @@ -29,7 +29,7 @@ * Represents a value that is yet to be bound to a machine location (such as a {@link RegisterValue} * or {@link StackSlot}) by a register allocator. */ -public final class Variable extends Value { +public final class Variable extends AllocatableValue { private static final long serialVersionUID = 4507578431686109809L; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Fri Mar 01 17:06:08 2013 +0100 @@ -179,7 +179,7 @@ }); } nodes.mark(earlyExit); - for (ValueProxyNode proxy : earlyExit.proxies()) { + for (ProxyNode proxy : earlyExit.proxies()) { nodes.mark(proxy); } } @@ -271,9 +271,9 @@ anchored.replaceFirstInput(earlyExit, merge); } - for (final ValueProxyNode vpn : earlyExit.proxies().snapshot()) { + for (final ProxyNode vpn : earlyExit.proxies().snapshot()) { final ValueNode replaceWith; - ValueProxyNode newVpn = getDuplicatedNode(vpn); + ProxyNode newVpn = getDuplicatedNode(vpn); if (newVpn != null) { PhiNode phi = graph.add(vpn.type() == PhiType.Value ? vpn.stamp() == StampFactory.virtual() ? new PhiNode(vpn.stamp(), merge) : new PhiNode(vpn.kind(), merge) : new PhiNode( vpn.type(), merge)); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -108,7 +108,7 @@ } public void removeProxies() { - for (ValueProxyNode vpn : proxies().snapshot()) { + for (ProxyNode vpn : proxies().snapshot()) { // can not use graph.replaceFloating because vpn.value may be null during killCFG vpn.replaceAtUsages(vpn.value()); vpn.safeDelete(); @@ -131,11 +131,11 @@ } public NodeIterable anchored() { - return usages().filter(isNotA(ValueProxyNode.class)); + return usages().filter(isNotA(ProxyNode.class)); } - public NodeIterable proxies() { - return usages().filter(ValueProxyNode.class); + public NodeIterable proxies() { + return usages().filter(ProxyNode.class); } public NodeIterable getBlockNodes() { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Fri Mar 01 17:06:08 2013 +0100 @@ -68,6 +68,12 @@ */ public static final int AFTER_EXCEPTION_BCI = -3; + /** + * This BCI should be used for frame states that cannot be the target of a deoptimization, like + * snippet frame states. + */ + public static final int INVALID_FRAMESTATE_BCI = -5; + @Input private FrameState outerFrameState; @Input private final NodeInputList values; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -109,6 +109,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -161,6 +161,11 @@ return true; } + @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + public FrameState stateDuring() { FrameState tempStateAfter = stateAfter(); FrameState stateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), kind()); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 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.nodes; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ValueNumberable; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A value proxy that is inserted in the frame state of a loop exit for any value that is created + * inside the loop (i.e. was not live on entry to the loop) and is (potentially) used after the + * loop. + */ +@NodeInfo(nameTemplate = "{p#type/s}Proxy") +public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable { + + @Input(notDataflow = true) private BeginNode proxyPoint; + @Input private ValueNode value; + private final PhiType type; + + public ProxyNode(ValueNode value, BeginNode exit, PhiType type) { + super(type == PhiType.Value ? value.stamp() : type.stamp); + this.type = type; + assert exit != null; + this.proxyPoint = exit; + this.value = value; + } + + public ValueNode value() { + return value; + } + + @Override + public boolean inferStamp() { + return updateStamp(value.stamp()); + } + + @Override + public Stamp stamp() { + return value().stamp(); + } + + public BeginNode proxyPoint() { + return proxyPoint; + } + + public PhiType type() { + return type; + } + + @Override + public boolean verify() { + assert value != null; + assert proxyPoint != null; + return super.verify(); + } + + @Override + public void generate(LIRGeneratorTool generator) { + assert type == PhiType.Memory; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (type == PhiType.Value && value.isConstant()) { + return value; + } + return this; + } + + @Override + public void virtualize(VirtualizerTool tool) { + if (type == PhiType.Value) { + State state = tool.getObjectState(value); + if (state != null && state.getState() == EscapeState.Virtual) { + tool.replaceWithVirtual(state.getVirtualObject()); + } + } + } +} diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -29,4 +29,8 @@ */ public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint { + @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Fri Mar 01 17:05:14 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 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.nodes; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.ValueNumberable; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * A value proxy that is inserted in the frame state of a loop exit for any value that is created - * inside the loop (i.e. was not live on entry to the loop) and is (potentially) used after the - * loop. - */ -public class ValueProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable { - - @Input(notDataflow = true) private BeginNode proxyPoint; - @Input private ValueNode value; - private final PhiType type; - - public ValueProxyNode(ValueNode value, BeginNode exit, PhiType type) { - super(value.stamp()); - this.type = type; - assert exit != null; - this.proxyPoint = exit; - this.value = value; - } - - public ValueNode value() { - return value; - } - - @Override - public boolean inferStamp() { - return updateStamp(value.stamp()); - } - - @Override - public Stamp stamp() { - return value().stamp(); - } - - public BeginNode proxyPoint() { - return proxyPoint; - } - - public PhiType type() { - return type; - } - - @Override - public boolean verify() { - assert value != null; - assert proxyPoint != null; - return super.verify(); - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - return value; - } - return this; - } - - @Override - public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(value); - if (state != null && state.getState() == EscapeState.Virtual) { - tool.replaceWithVirtual(state.getVirtualObject()); - } - } -} diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Fri Mar 01 17:06:08 2013 +0100 @@ -108,9 +108,38 @@ return loops; } + public void clearNodeToBlock() { + nodeToBlock.clear(); + for (Block block : reversePostOrder) { + identifyBlock(block, block.beginNode); + } + } + protected static final int BLOCK_ID_INITIAL = -1; protected static final int BLOCK_ID_VISITED = -2; + private void identifyBlock(Block block, BeginNode begin) { + block.beginNode = begin; + Node cur = begin; + Node last; + do { + assert !cur.isDeleted(); + + assert nodeToBlock.get(cur) == null; + nodeToBlock.set(cur, block); + if (cur instanceof MergeNode) { + for (PhiNode phi : ((MergeNode) cur).phis()) { + nodeToBlock.set(phi, block); + } + } + + last = cur; + cur = cur.successors().first(); + } while (cur != null && !(cur instanceof BeginNode)); + + block.endNode = (FixedNode) last; + } + private void identifyBlocks() { // Find all block headers int numBlocks = 0; @@ -118,26 +147,7 @@ if (node instanceof BeginNode) { Block block = new Block(); numBlocks++; - - block.beginNode = (BeginNode) node; - Node cur = node; - Node last; - do { - assert !cur.isDeleted(); - - assert nodeToBlock.get(cur) == null; - nodeToBlock.set(cur, block); - if (cur instanceof MergeNode) { - for (PhiNode phi : ((MergeNode) cur).phis()) { - nodeToBlock.set(phi, block); - } - } - - last = cur; - cur = cur.successors().first(); - } while (cur != null && !(cur instanceof BeginNode)); - - block.endNode = (FixedNode) last; + identifyBlock(block, (BeginNode) node); } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -53,7 +53,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(gen.makeAddress(location(), object()), getNullCheck())); + gen.setResult(this, location().generateLoad(gen, object(), getNullCheck())); } @Override diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -79,4 +79,19 @@ } return this; } + + @Override + public Value generateLea(LIRGeneratorTool gen, ValueNode base) { + return gen.emitLea(gen.operand(base), displacement(), gen.operand(index()), indexScaling()); + } + + @Override + public Value generateLoad(LIRGeneratorTool gen, ValueNode base, boolean canTrap) { + return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), canTrap); + } + + @Override + public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, boolean canTrap) { + gen.emitStore(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), gen.operand(value), canTrap); + } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -25,6 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ValueNumberable; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -42,27 +43,37 @@ private Object locationIdentity; /** + * Creates a new unique location identity for read and write operations. + * + * @param name the name of the new location identity, for debugging purposes + * @return the new location identity + */ + public static Object createLocation(final String name) { + return new Object() { + + @Override + public String toString() { + return name; + } + }; + } + + /** * Denotes any location. A write to such a location kills all values in a memory map during an * analysis of memory accesses in a graph. */ - public static final Object ANY_LOCATION = new Object() { + public static final Object ANY_LOCATION = createLocation("ANY_LOCATION"); - @Override - public String toString() { - return "ANY_LOCATION"; - } - }; + /** + * Denotes an unknown location. A read from this location cannot be moved or coalesced with + * other reads because its interaction with other reads is not known. + */ + public static final Object UNKNOWN_LOCATION = createLocation("UNKNOWN_LOCATION"); /** * Denotes the location of a value that is guaranteed to be final. */ - public static final Object FINAL_LOCATION = new Object() { - - @Override - public String toString() { - return "FINAL_LOCATION"; - } - }; + public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION"); public static Object getArrayLocation(Kind elementKind) { return elementKind; @@ -96,4 +107,16 @@ public void generate(LIRGeneratorTool generator) { // nothing to do... } + + public Value generateLea(LIRGeneratorTool gen, ValueNode base) { + return gen.emitLea(gen.operand(base), displacement(), Value.ILLEGAL, 0); + } + + public Value generateLoad(LIRGeneratorTool gen, ValueNode base, boolean canTrap) { + return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, canTrap); + } + + public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, boolean canTrap) { + gen.emitStore(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, gen.operand(value), canTrap); + } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -43,6 +43,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void generate(LIRGeneratorTool generator) { generator.emitMembar(barriers); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Fri Mar 01 17:06:08 2013 +0100 @@ -22,6 +22,21 @@ */ package com.oracle.graal.nodes.extended; +import com.oracle.graal.nodes.*; + +/** + * This interface marks is used for subclasses of {@link FixedNode} that kill a set of memory + * locations represented by a location identity (i.e. change a value at one or more locations that + * belong to this location identity). + */ public interface MemoryCheckpoint { + /** + * This method is used to determine which set of memory locations is killed by this node. + * Returning the special value {@link LocationNode#ANY_LOCATION} will kill all memory locations. + * + * @return the identity of the location killed by this node. + */ + Object getLocationIdentity(); + } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -51,7 +51,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(gen.makeAddress(location(), object()), getNullCheck())); + gen.setResult(this, location().generateLoad(gen, object(), getNullCheck())); } @Override diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -49,6 +49,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void generate(LIRGeneratorTool gen) { gen.visitRuntimeCall(this); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -93,7 +93,7 @@ if (kind() != object.kind()) { assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object.kind()) : "unsafe cast cannot be used to change the size of a value"; Value result = generator.newVariable(kind()); - generator.emitMove(generator.operand(object), result); + generator.emitMove(result, generator.operand(object)); generator.setResult(this, result); } else { // The LIR only cares about the kind of an operand, not the actual type of an object. So diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -33,7 +33,7 @@ * Store of a value at a location specified as an offset relative to an object. No null check is * performed before the store. */ -public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable { +public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable, MemoryCheckpoint { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -72,6 +72,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void virtualize(VirtualizerTool tool) { State state = tool.getObjectState(object()); if (state != null && state.getState() == EscapeState.Virtual) { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -37,6 +37,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void generate(LIRGeneratorTool generator) { // nothing to do... } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -29,7 +29,7 @@ /** * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}. */ -public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable { +public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -59,9 +59,14 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.emitStore(gen.makeAddress(location(), object()), gen.operand(value()), getNullCheck()); + location().generateStore(gen, object(), value(), getNullCheck()); } @NodeIntrinsic public static native void writeMemory(Object object, Object value, Object location); + + @Override + public Object getLocationIdentity() { + return location().locationIdentity(); + } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -71,6 +71,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void generate(LIRGeneratorTool gen) { gen.visitCompareAndSwap(this); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -42,6 +42,11 @@ } @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + + @Override public void generate(LIRGeneratorTool gen) { gen.visitExceptionObject(this); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -40,6 +40,11 @@ super(object); } + @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -41,6 +41,11 @@ super(object); } + @Override + public Object getLocationIdentity() { + return LocationNode.ANY_LOCATION; + } + public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Fri Mar 01 17:06:08 2013 +0100 @@ -45,16 +45,6 @@ */ public abstract boolean canInlineConstant(Constant c); - /** - * Checks whether the supplied constant can be used without loading it into a register for store - * operations, i.e., on the right hand side of a memory access. - * - * @param c The constant to check. - * @return True if the constant can be used directly, false if the constant needs to be in a - * register. - */ - public abstract boolean canStoreConstant(Constant c); - public abstract RegisterAttributes attributes(Register register); public abstract Value operand(ValueNode object); @@ -63,27 +53,17 @@ public abstract Value setResult(ValueNode x, Value operand); - public abstract Address makeAddress(LocationNode location, ValueNode object); - - public abstract Address makeAddress(Kind kind, Value base, int displacement); - - public Address makeAddress(Kind kind, Value base) { - return makeAddress(kind, base, 0); - } - - public Address makeAddress(Kind kind, int address) { - return makeAddress(kind, Value.ILLEGAL, address); - } - public abstract Value emitMove(Value input); - public abstract void emitMove(Value src, Value dst); + public abstract void emitMove(Value dst, Value src); - public abstract Value emitLoad(Value loadAddress, boolean canTrap); + public abstract Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap); - public abstract void emitStore(Value storeAddress, Value input, boolean canTrap); + public abstract void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap); - public abstract Value emitLea(Value address); + public abstract Value emitLea(Value base, int displacement, Value index, int scale); + + public abstract Value emitLea(StackSlot slot); public abstract Value emitNegate(Value input); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Fri Mar 01 17:06:08 2013 +0100 @@ -140,18 +140,18 @@ ValueNode singleValue = phiNode.singleValue(); if (singleValue != null) { Collection phiUsages = phiNode.usages().filter(PhiNode.class).snapshot(); - Collection proxyUsages = phiNode.usages().filter(ValueProxyNode.class).snapshot(); + Collection proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot(); ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue); for (PhiNode phi : phiUsages) { checkRedundantPhi(phi); } - for (ValueProxyNode proxy : proxyUsages) { + for (ProxyNode proxy : proxyUsages) { checkRedundantProxy(proxy); } } } - public static void checkRedundantProxy(ValueProxyNode vpn) { + public static void checkRedundantProxy(ProxyNode vpn) { BeginNode proxyPoint = vpn.proxyPoint(); if (proxyPoint instanceof LoopExitNode) { LoopExitNode exit = (LoopExitNode) proxyPoint; @@ -164,12 +164,12 @@ } if (vpnValue == v2) { Collection phiUsages = vpn.usages().filter(PhiNode.class).snapshot(); - Collection proxyUsages = vpn.usages().filter(ValueProxyNode.class).snapshot(); + Collection proxyUsages = vpn.usages().filter(ProxyNode.class).snapshot(); ((StructuredGraph) vpn.graph()).replaceFloating(vpn, vpnValue); for (PhiNode phi : phiUsages) { checkRedundantPhi(phi); } - for (ValueProxyNode proxy : proxyUsages) { + for (ProxyNode proxy : proxyUsages) { checkRedundantProxy(proxy); } return; @@ -185,7 +185,7 @@ GraphUtil.checkRedundantPhi(phi); } for (LoopExitNode exit : begin.loopExits()) { - for (ValueProxyNode vpn : exit.proxies().snapshot()) { + for (ProxyNode vpn : exit.proxies().snapshot()) { GraphUtil.checkRedundantProxy(vpn); } } @@ -259,8 +259,8 @@ public static ValueNode unProxify(ValueNode proxy) { ValueNode v = proxy; - while (v instanceof ValueProxyNode) { - v = ((ValueProxyNode) v).value(); + while (v instanceof ProxyNode) { + v = ((ProxyNode) v).value(); } return v; } @@ -293,8 +293,8 @@ public static ValueNode originalValue(ValueNode proxy) { ValueNode v = proxy; do { - if (v instanceof ValueProxyNode) { - v = ((ValueProxyNode) v).value(); + if (v instanceof ProxyNode) { + v = ((ProxyNode) v).value(); } else if (v instanceof PhiNode) { v = ((PhiNode) v).singleValue(); } else { @@ -308,8 +308,8 @@ NodeWorkList worklist = proxy.graph().createNodeWorkList(); worklist.add(proxy); for (Node node : worklist) { - if (node instanceof ValueProxyNode) { - worklist.add(((ValueProxyNode) node).value()); + if (node instanceof ProxyNode) { + worklist.add(((ProxyNode) node).value()); } else if (node instanceof PhiNode) { worklist.addAll(((PhiNode) node).values()); } else { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -37,11 +37,14 @@ public class CullFrameStatesPhase extends Phase { private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled"); + private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed"); @Override protected void run(StructuredGraph graph) { + int initialNodes = graph.getNodeCount(); new CullFrameStates(graph.start(), new State(null)).apply(); + metricNodesRemoved.add(initialNodes - graph.getNodeCount()); } public static class State implements MergeableState { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -29,271 +29,218 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; public class FloatingReadPhase extends Phase { - private IdentityHashMap> loopEndStatesMap; - - private static class LoopState { - - public LoopBeginNode loopBegin; - public MemoryMap state; - public IdentityHashMap loopPhiLocations = new IdentityHashMap<>(); - public ValueNode loopEntryAnyLocation; - - public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) { - this.loopBegin = loopBegin; - this.state = state; - this.loopEntryAnyLocation = loopEntryAnyLocation; - } - - @Override - public String toString() { - return "State@" + loopBegin; - } - } - - private class MemoryMap implements MergeableState { + private static class MemoryMap { private IdentityHashMap lastMemorySnapshot; - private LinkedList loops; public MemoryMap(MemoryMap memoryMap) { lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); - loops = new LinkedList<>(memoryMap.loops); + } + + public MemoryMap(StartNode start) { + this(); + lastMemorySnapshot.put(LocationNode.ANY_LOCATION, start); } public MemoryMap() { lastMemorySnapshot = new IdentityHashMap<>(); - loops = new LinkedList<>(); + } + + private ValueNode getLastLocationAccess(Object locationIdentity) { + ValueNode lastLocationAccess; + if (locationIdentity == LocationNode.FINAL_LOCATION) { + return null; + } else { + lastLocationAccess = lastMemorySnapshot.get(locationIdentity); + if (lastLocationAccess == null) { + lastLocationAccess = lastMemorySnapshot.get(LocationNode.ANY_LOCATION); + assert lastLocationAccess != null; + } + return lastLocationAccess; + } } @Override public String toString() { - return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString(); - } - - @SuppressWarnings("unchecked") - @Override - public boolean merge(MergeNode merge, List withStates) { - if (withStates.size() == 0) { - return true; - } - - int minLoops = loops.size(); - for (MemoryMap other : withStates) { - int otherLoops = other.loops.size(); - if (otherLoops < minLoops) { - minLoops = otherLoops; - } - } - while (loops.size() > minLoops) { - loops.pop(); - } - for (MemoryMap other : withStates) { - while (other.loops.size() > minLoops) { - other.loops.pop(); - } - } - - Set keys = new HashSet<>(); - for (Object key : lastMemorySnapshot.keySet()) { - keys.add(key); - } - for (MemoryMap other : withStates) { - assert other.loops.size() == loops.size(); - assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin; - for (Object key : other.lastMemorySnapshot.keySet()) { - keys.add(key); - } - } - IdentityHashMap newMemorySnapshot = (IdentityHashMap) lastMemorySnapshot.clone(); - - for (Object key : keys) { - ValueNode merged = lastMemorySnapshot.get(key); - if (merged == null) { - merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - int mergedStatesCount = 1; - boolean isPhi = false; - for (MemoryMap other : withStates) { - ValueNode otherValue = other.lastMemorySnapshot.get(key); - if (otherValue == null) { - otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - if (isPhi) { - ((PhiNode) merged).addInput(otherValue); - } else if (merged != otherValue) { - PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); - for (int j = 0; j < mergedStatesCount; j++) { - phi.addInput(merged); - } - phi.addInput(otherValue); - merged = phi; - isPhi = true; - newMemorySnapshot.put(key, phi); - } - mergedStatesCount++; - } - } - - lastMemorySnapshot = newMemorySnapshot; - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION)); - for (Map.Entry entry : lastMemorySnapshot.entrySet()) { - PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin)); - phi.addInput(entry.getValue()); - entry.setValue(phi); - loopState.loopPhiLocations.put(phi, entry.getKey()); - } - loops.push(loopState); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - loopEndStatesMap.put(loopBegin, loopEndStates); - tryFinishLoopPhis(this, loopBegin); - } - - @Override - public void afterSplit(BeginNode node) { - // nothing - } - - @Override - public MemoryMap clone() { - return new MemoryMap(this); + return "Map=" + lastMemorySnapshot.toString(); } } + private final Map> modifiedInLoops = new IdentityHashMap<>(); + @Override protected void run(StructuredGraph graph) { - loopEndStatesMap = new IdentityHashMap<>(); - new PostOrderNodeIterator(graph.start(), new MemoryMap()) { - - @Override - protected void node(FixedNode node) { - processNode(node, state); - } - }.apply(); - } - - private void processNode(FixedNode node, MemoryMap state) { - if (node instanceof ReadNode) { - processRead((ReadNode) node, state); - } else if (node instanceof WriteNode) { - processWrite((WriteNode) node, state); - } else if (node instanceof MemoryCheckpoint) { - processCheckpoint((MemoryCheckpoint) node, state); - } else if (node instanceof LoopExitNode) { - processLoopExit((LoopExitNode) node, state); - } - } - - private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { - processAnyLocationWrite((ValueNode) checkpoint, state); + ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(), graph.start(), new HashSet<>(), null); + ReentrantNodeIterator.apply(new FloatingReadClosure(), graph.start(), new MemoryMap(graph.start()), null); } - private static void processWrite(WriteNode writeNode, MemoryMap state) { - if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) { - processAnyLocationWrite(writeNode, state); + private class CollectMemoryCheckpointsClosure extends NodeIteratorClosure> { + + @Override + protected void processNode(FixedNode node, Set currentState) { + if (node instanceof MemoryCheckpoint) { + currentState.add(((MemoryCheckpoint) node).getLocationIdentity()); + } } - state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode); - } - private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) { - for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(modifiying); + @Override + protected Set merge(MergeNode merge, List> states) { + Set result = new HashSet<>(); + for (Set other : states) { + result.addAll(other); + } + return result; } - state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying); - state.loops.clear(); - } - private void processRead(ReadNode readNode, MemoryMap state) { - StructuredGraph graph = (StructuredGraph) readNode.graph(); - assert readNode.getNullCheck() == false; - Object locationIdentity = readNode.location().locationIdentity(); - ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity); - FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies())); - floatingRead.setNullCheck(readNode.getNullCheck()); - ValueAnchorNode anchor = null; - for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) { - if (anchor == null) { - anchor = graph.add(new ValueAnchorNode()); + @Override + protected Set afterSplit(BeginNode node, Set oldState) { + return new HashSet<>(oldState); + } + + @Override + protected Map> processLoop(LoopBeginNode loop, Set initialState) { + LoopInfo> loopInfo = ReentrantNodeIterator.processLoop(this, loop, new HashSet<>()); + Set modifiedLocations = new HashSet<>(); + for (Set end : loopInfo.endStates.values()) { + modifiedLocations.addAll(end); } - anchor.addAnchoredNode(guard); + for (Set exit : loopInfo.exitStates.values()) { + exit.addAll(modifiedLocations); + exit.addAll(initialState); + } + assert !modifiedLocations.contains(LocationNode.FINAL_LOCATION); + modifiedInLoops.put(loop, modifiedLocations); + return loopInfo.exitStates; } - if (anchor != null) { - graph.addAfterFixed(readNode, anchor); - } - graph.replaceFixedWithFloating(readNode, floatingRead); + } - private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) { - ValueNode lastLocationAccess; - if (locationIdentity == LocationNode.FINAL_LOCATION) { - lastLocationAccess = null; - } else { - lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity); - if (lastLocationAccess == null) { - LoopState lastLoop = state.loops.peek(); - if (lastLoop == null) { - lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } else { - ValueNode phiInit; - if (state.loops.size() > 1) { - phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity); - } else { - phiInit = lastLoop.loopEntryAnyLocation; + private class FloatingReadClosure extends NodeIteratorClosure { + + @Override + protected void processNode(FixedNode node, MemoryMap state) { + if (node instanceof ReadNode) { + processRead((ReadNode) node, state); + } else if (node instanceof MemoryCheckpoint) { + processCheckpoint((MemoryCheckpoint) node, state); + } + } + + private void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { + if (checkpoint.getLocationIdentity() == LocationNode.ANY_LOCATION) { + state.lastMemorySnapshot.clear(); + } + state.lastMemorySnapshot.put(checkpoint.getLocationIdentity(), (ValueNode) checkpoint); + } + + private void processRead(ReadNode readNode, MemoryMap state) { + StructuredGraph graph = (StructuredGraph) readNode.graph(); + assert readNode.getNullCheck() == false; + Object locationIdentity = readNode.location().locationIdentity(); + if (locationIdentity != LocationNode.UNKNOWN_LOCATION) { + ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity); + FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies())); + floatingRead.setNullCheck(readNode.getNullCheck()); + ValueAnchorNode anchor = null; + for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) { + if (anchor == null) { + anchor = graph.add(new ValueAnchorNode()); + graph.addAfterFixed(readNode, anchor); } - PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin)); - phi.addInput(phiInit); - lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi); - lastLoop.loopPhiLocations.put(phi, locationIdentity); - tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin); - lastLocationAccess = phi; + anchor.addAnchoredNode(guard); } - state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess); + graph.replaceFixedWithFloating(readNode, floatingRead); } } - return lastLocationAccess; - } + + @Override + protected MemoryMap merge(MergeNode merge, List states) { + MemoryMap newState = new MemoryMap(); - private static void processLoopExit(LoopExitNode exit, MemoryMap state) { - for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory))); - } - if (!state.loops.isEmpty()) { - state.loops.pop(); - } - } + Set keys = new HashSet<>(); + for (MemoryMap other : states) { + keys.addAll(other.lastMemorySnapshot.keySet()); + } + assert !keys.contains(LocationNode.FINAL_LOCATION); - private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) { - List loopEndStates = loopEndStatesMap.get(loopBegin); - if (loopEndStates == null) { - return; - } - LoopState loopState = loopMemory.loops.get(0); - int i = 0; - while (loopState.loopBegin != loopBegin) { - loopState = loopMemory.loops.get(++i); + for (Object key : keys) { + int mergedStatesCount = 0; + boolean isPhi = false; + ValueNode merged = null; + for (MemoryMap state : states) { + ValueNode last = state.getLastLocationAccess(key); + if (isPhi) { + ((PhiNode) merged).addInput(last); + } else { + if (merged == last) { + // nothing to do + } else if (merged == null) { + merged = last; + } else { + PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); + for (int j = 0; j < mergedStatesCount; j++) { + phi.addInput(merged); + } + phi.addInput(last); + merged = phi; + isPhi = true; + } + } + mergedStatesCount++; + } + newState.lastMemorySnapshot.put(key, merged); + } + return newState; } - for (PhiNode phi : loopBegin.phis()) { - if (phi.type() == PhiType.Memory && phi.valueCount() == 1) { - Object location = loopState.loopPhiLocations.get(phi); - assert location != null : "unknown location for " + phi; - for (MemoryMap endState : loopEndStates) { - ValueNode otherNode = endState.lastMemorySnapshot.get(location); - if (otherNode == null) { - otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - phi.addInput(otherNode); + + @Override + protected MemoryMap afterSplit(BeginNode node, MemoryMap oldState) { + return new MemoryMap(oldState); + } + + @Override + protected Map processLoop(LoopBeginNode loop, MemoryMap initialState) { + Set modifiedLocations = modifiedInLoops.get(loop); + if (modifiedLocations.contains(LocationNode.ANY_LOCATION)) { + // create phis for all locations if ANY is modified in the loop + modifiedLocations = new HashSet<>(modifiedLocations); + modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet()); + } + + Map phis = new HashMap<>(); + for (Object location : modifiedLocations) { + PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop)); + phi.addInput(initialState.getLastLocationAccess(location)); + phis.put(location, phi); + initialState.lastMemorySnapshot.put(location, phi); + } + + LoopInfo loopInfo = ReentrantNodeIterator.processLoop(this, loop, initialState); + + for (Map.Entry entry : loopInfo.endStates.entrySet()) { + int endIndex = loop.phiPredecessorIndex(entry.getKey()); + for (Map.Entry phiEntry : phis.entrySet()) { + Object key = phiEntry.getKey(); + PhiNode phi = phiEntry.getValue(); + phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key)); } } + for (Map.Entry entry : loopInfo.exitStates.entrySet()) { + LoopExitNode exit = entry.getKey(); + MemoryMap state = entry.getValue(); + for (Object location : modifiedLocations) { + ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location); + if (lastAccessAtExit != null) { + state.lastMemorySnapshot.put(location, loop.graph().add(new ProxyNode(lastAccessAtExit, exit, PhiType.Memory))); + } + } + } + return loopInfo.exitStates; } } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -24,6 +24,7 @@ import java.lang.reflect.*; import java.util.*; +import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -127,26 +128,32 @@ return cachedGraph; } } - StructuredGraph newGraph = new StructuredGraph(method); - if (plan != null) { - plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); - } - assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; + final StructuredGraph newGraph = new StructuredGraph(method); + return Debug.scope("InlineGraph", newGraph, new Callable() { + + @Override + public StructuredGraph call() throws Exception { + if (plan != null) { + plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); + } + assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(newGraph); - new ComputeProbabilityPhase().apply(newGraph); - } - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(newGraph); - } - if (GraalOptions.CullFrameStates) { - new CullFrameStatesPhase().apply(newGraph); - } - if (GraalOptions.CacheGraphs && cache != null) { - cache.put(newGraph); - } - return newGraph; + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(newGraph); + new ComputeProbabilityPhase().apply(newGraph); + } + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(runtime, assumptions).apply(newGraph); + } + if (GraalOptions.CullFrameStates) { + new CullFrameStatesPhase().apply(newGraph); + } + if (GraalOptions.CacheGraphs && cache != null) { + cache.put(newGraph); + } + return newGraph; + } + }); } private interface InliningDecision { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Fri Mar 01 17:06:08 2013 +0100 @@ -1122,7 +1122,7 @@ } else { // only handle the outermost frame states if (frameState.outerFrameState() == null) { - assert frameState.method() == inlineGraph.method(); + assert frameState.bci == FrameState.INVALID_FRAMESTATE_BCI || frameState.method() == inlineGraph.method(); if (outerFrameState == null) { outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind()); outerFrameState.setDuringCall(true); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -59,8 +59,8 @@ if (visited.isMarked(lastLocationAccess)) { return true; // dataflow loops must come from Phis assume them ok until proven wrong } - if (lastLocationAccess instanceof ValueProxyNode) { - return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited); + if (lastLocationAccess instanceof ProxyNode) { + return isWrites(n, ((ProxyNode) lastLocationAccess).value(), visited); } if (lastLocationAccess instanceof WriteNode) { WriteNode other = (WriteNode) lastLocationAccess; @@ -83,10 +83,10 @@ if (exisiting != null) { return exisiting; } - if (lastLocationAccess instanceof ValueProxyNode) { - ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess; + if (lastLocationAccess instanceof ProxyNode) { + ProxyNode proxy = (ProxyNode) lastLocationAccess; ValueNode value = getValue(n, proxy.value(), nodeMap); - return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value)); + return lastLocationAccess.graph().add(new ProxyNode(value, proxy.proxyPoint(), PhiType.Value)); } if (lastLocationAccess instanceof WriteNode) { return ((WriteNode) lastLocationAccess).value(); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -23,14 +23,17 @@ package com.oracle.graal.phases.common; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.*; import com.oracle.graal.phases.*; public class RemoveValueProxyPhase extends Phase { @Override protected void run(StructuredGraph graph) { - for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) { - graph.replaceFloating(vpn, vpn.value()); + for (ProxyNode vpn : graph.getNodes(ProxyNode.class)) { + if (vpn.type() == PhiType.Value) { + graph.replaceFloating(vpn, vpn.value()); + } } for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) { FrameState stateAfter = exit.stateAfter(); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Fri Mar 01 17:06:08 2013 +0100 @@ -150,7 +150,7 @@ public static boolean ExitVMOnException = true; // Code generator settings - public static boolean CheckCastElimination = true; + public static boolean ConditionalElimination = true; public static boolean CullFrameStates = ____; public static boolean UseProfilingInformation = true; static boolean RemoveNeverExecutedCode = true; @@ -168,6 +168,8 @@ public static boolean CanOmitFrame = true; public static int SafepointPollOffset = 256; + public static boolean MemoryAwareScheduling = true; + // Translating tableswitch instructions public static int MinimumJumpTableSize = 5; public static int RangeTestsSwitchDensity = 5; diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Fri Mar 01 17:06:08 2013 +0100 @@ -29,54 +29,49 @@ public final class ReentrantBlockIterator { - public abstract static class MergeableBlockState { + public static class LoopInfo { - public abstract T cloneState(); + public final List endStates = new ArrayList<>(); + public final List exitStates = new ArrayList<>(); } - public static class LoopInfo> { + public abstract static class BlockIteratorClosure { - public final List endStates = new ArrayList<>(); - public final List exitStates = new ArrayList<>(); - } - - public abstract static class BlockIteratorClosure> { + protected abstract void processBlock(Block block, StateT currentState); - protected abstract void processBlock(Block block, T currentState); - - protected abstract T merge(MergeNode merge, List states); + protected abstract StateT merge(MergeNode merge, List states); - protected abstract T afterSplit(FixedNode node, T oldState); + protected abstract StateT afterSplit(FixedNode node, StateT oldState); - protected abstract List processLoop(Loop loop, T initialState); + protected abstract List processLoop(Loop loop, StateT initialState); } private ReentrantBlockIterator() { // no instances allowed } - public static > LoopInfo processLoop(BlockIteratorClosure closure, Loop loop, T initialState) { - IdentityHashMap blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks)); + public static LoopInfo processLoop(BlockIteratorClosure closure, Loop loop, StateT initialState) { + IdentityHashMap blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks)); - LoopInfo info = new LoopInfo<>(); + LoopInfo info = new LoopInfo<>(); List predecessors = loop.header.getPredecessors(); for (int i = 1; i < predecessors.size(); i++) { info.endStates.add(blockEndStates.get(predecessors.get(i).getEndNode())); } for (Block loopExit : loop.exits) { assert loopExit.getPredecessorCount() == 1; - T exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode()); + StateT exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode()); assert exitState != null; info.exitStates.add(exitState); } return info; } - public static > IdentityHashMap apply(BlockIteratorClosure closure, Block start, T initialState, Set boundary) { + public static IdentityHashMap apply(BlockIteratorClosure closure, Block start, StateT initialState, Set boundary) { Deque blockQueue = new ArrayDeque<>(); - IdentityHashMap blockEndStates = new IdentityHashMap<>(); + IdentityHashMap blockEndStates = new IdentityHashMap<>(); - T state = initialState; + StateT state = initialState; Block current = start; do { @@ -98,7 +93,7 @@ LoopBeginNode loopBegin = loop.loopBegin(); assert successor.getBeginNode() == loopBegin; - List exitStates = closure.processLoop(loop, state); + List exitStates = closure.processLoop(loop, state); int i = 0; assert loop.exits.size() == exitStates.size(); @@ -123,8 +118,8 @@ blockEndStates.put(end, state); MergeNode merge = end.merge(); boolean endsVisited = true; - for (int i = 0; i < merge.forwardEndCount(); i++) { - if (!blockEndStates.containsKey(merge.forwardEndAt(i))) { + for (EndNode forwardEnd : merge.forwardEnds()) { + if (!blockEndStates.containsKey(forwardEnd)) { endsVisited = false; break; } @@ -157,9 +152,9 @@ current = blockQueue.removeFirst(); if (current.getPredecessors().size() > 1) { MergeNode merge = (MergeNode) current.getBeginNode(); - ArrayList states = new ArrayList<>(merge.forwardEndCount()); + ArrayList states = new ArrayList<>(merge.forwardEndCount()); for (int i = 0; i < merge.forwardEndCount(); i++) { - T other = blockEndStates.get(merge.forwardEndAt(i)); + StateT other = blockEndStates.get(merge.forwardEndAt(i)); assert other != null; states.add(other); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java Fri Mar 01 17:06:08 2013 +0100 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011, 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.phases.graph; + +import java.util.*; + +import com.oracle.graal.graph.NodeClass.NodeClassIterator; +import com.oracle.graal.nodes.*; + +public final class ReentrantNodeIterator { + + public static class LoopInfo { + + public final Map endStates = new IdentityHashMap<>(4); + public final Map exitStates = new IdentityHashMap<>(2); + } + + public abstract static class NodeIteratorClosure { + + protected abstract void processNode(FixedNode node, StateT currentState); + + protected abstract StateT merge(MergeNode merge, List states); + + protected abstract StateT afterSplit(BeginNode node, StateT oldState); + + protected abstract Map processLoop(LoopBeginNode loop, StateT initialState); + } + + private ReentrantNodeIterator() { + // no instances allowed + } + + public static LoopInfo processLoop(NodeIteratorClosure closure, LoopBeginNode loop, StateT initialState) { + HashSet boundary = new HashSet<>(); + for (LoopExitNode exit : loop.loopExits()) { + boundary.add(exit); + } + Map blockEndStates = apply(closure, loop, initialState, boundary); + + LoopInfo info = new LoopInfo<>(); + for (LoopEndNode end : loop.loopEnds()) { + assert blockEndStates.containsKey(end) : "no end state for " + end; + info.endStates.put(end, blockEndStates.get(end)); + } + for (LoopExitNode exit : loop.loopExits()) { + assert blockEndStates.containsKey(exit) : "no exit state for " + exit; + info.exitStates.put(exit, blockEndStates.get(exit)); + } + return info; + } + + public static Map apply(NodeIteratorClosure closure, FixedNode start, StateT initialState, Set boundary) { + Deque nodeQueue = new ArrayDeque<>(); + IdentityHashMap blockEndStates = new IdentityHashMap<>(); + + StateT state = initialState; + FixedNode current = start; + do { + while (current instanceof FixedWithNextNode) { + if (boundary != null && boundary.contains(current)) { + blockEndStates.put(current, state); + current = null; + } else { + FixedNode next = ((FixedWithNextNode) current).next(); + closure.processNode(current, state); + current = next; + } + } + + if (current != null) { + closure.processNode(current, state); + + NodeClassIterator successors = current.successors().iterator(); + if (!successors.hasNext()) { + if (current instanceof LoopEndNode) { + blockEndStates.put(current, state); + } else if (current instanceof EndNode) { + // add the end node and see if the merge is ready for processing + MergeNode merge = ((EndNode) current).merge(); + if (merge instanceof LoopBeginNode) { + Map loopExitState = closure.processLoop((LoopBeginNode) merge, state); + for (Map.Entry entry : loopExitState.entrySet()) { + blockEndStates.put(entry.getKey(), entry.getValue()); + nodeQueue.add(entry.getKey()); + } + } else { + assert !blockEndStates.containsKey(current); + blockEndStates.put(current, state); + boolean endsVisited = true; + for (EndNode forwardEnd : merge.forwardEnds()) { + if (!blockEndStates.containsKey(forwardEnd)) { + endsVisited = false; + break; + } + } + if (endsVisited) { + ArrayList states = new ArrayList<>(merge.forwardEndCount()); + for (int i = 0; i < merge.forwardEndCount(); i++) { + EndNode forwardEnd = merge.forwardEndAt(i); + assert blockEndStates.containsKey(forwardEnd); + StateT other = blockEndStates.get(forwardEnd); + states.add(other); + } + state = closure.merge(merge, states); + current = merge; + continue; + } + } + } + } else { + FixedNode firstSuccessor = (FixedNode) successors.next(); + if (!successors.hasNext()) { + current = firstSuccessor; + continue; + } else { + while (successors.hasNext()) { + BeginNode successor = (BeginNode) successors.next(); + blockEndStates.put(successor, closure.afterSplit(successor, state)); + nodeQueue.add(successor); + } + state = closure.afterSplit((BeginNode) firstSuccessor, state); + current = firstSuccessor; + continue; + } + } + } + + // get next queued block + if (nodeQueue.isEmpty()) { + return blockEndStates; + } else { + current = nodeQueue.removeFirst(); + state = blockEndStates.get(current); + assert !(current instanceof MergeNode) && current instanceof BeginNode; + } + } while (true); + } +} diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -28,12 +28,102 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Verbosity; 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.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; -public class SchedulePhase extends Phase { +public final class SchedulePhase extends Phase { + + public static enum SchedulingStrategy { + EARLIEST, LATEST, LATEST_OUT_OF_LOOPS + } + + /** + * This closure iterates over all nodes of a scheduled graph (it expects a + * {@link SchedulingStrategy#EARLIEST} schedule) and keeps a list of "actuve" reads. Whenever it + * encounters a read, it adds it to the active reads. Whenever it encounters a memory + * checkpoint, it adds all reads that need to be committed before this checkpoint to the + * "phantom" usages and inputs, so that the read is scheduled before the checkpoint afterwards. + * + * At merges, the intersection of all sets of active reads is calculated. A read that was + * committed within one predecessor branch cannot be scheduled after the merge anyway. + * + * Similarly for loops, all reads that are killed somewhere within the loop are removed from the + * exits' active reads, since they cannot be scheduled after the exit anyway. + */ + private class MemoryScheduleClosure extends BlockIteratorClosure> { + + @Override + protected void processBlock(Block block, HashSet currentState) { + for (Node node : getBlockToNodesMap().get(block)) { + if (node instanceof FloatingReadNode) { + currentState.add((FloatingReadNode) node); + } else if (node instanceof MemoryCheckpoint) { + Object identity = ((MemoryCheckpoint) node).getLocationIdentity(); + for (Iterator iter = currentState.iterator(); iter.hasNext();) { + FloatingReadNode read = iter.next(); + FixedNode fixed = (FixedNode) node; + if (identity == LocationNode.ANY_LOCATION || read.location().locationIdentity() == identity) { + addPhantomReference(read, fixed); + } + } + } + } + } + + public void addPhantomReference(FloatingReadNode read, FixedNode fixed) { + List usageList = phantomUsages.get(read); + if (usageList == null) { + phantomUsages.put(read, usageList = new ArrayList<>()); + } + usageList.add(fixed); + List inputList = phantomInputs.get(fixed); + if (inputList == null) { + phantomInputs.put(fixed, inputList = new ArrayList<>()); + } + inputList.add(read); + } + + @Override + protected HashSet merge(MergeNode merge, List> states) { + HashSet state = new HashSet<>(states.get(0)); + for (int i = 1; i < states.size(); i++) { + state.retainAll(states.get(i)); + } + return state; + } + + @Override + protected HashSet afterSplit(FixedNode node, HashSet oldState) { + return new HashSet<>(oldState); + } + + @Override + protected List> processLoop(Loop loop, HashSet state) { + LoopInfo> info = ReentrantBlockIterator.processLoop(this, loop, new HashSet<>(state)); + + List> loopEndStates = info.endStates; + + // collect all reads that were killed in some branch within the loop + Set killedReads = new HashSet<>(state); + Set survivingReads = new HashSet<>(loopEndStates.get(0)); + for (int i = 1; i < loopEndStates.size(); i++) { + survivingReads.retainAll(loopEndStates.get(i)); + } + killedReads.removeAll(survivingReads); + + // reads that were killed within the loop cannot be scheduled after the loop anyway + for (HashSet exitState : info.exitStates) { + exitState.removeAll(killedReads); + } + return info.exitStates; + } + } private ControlFlowGraph cfg; private NodeMap earliestCache; @@ -42,6 +132,8 @@ * Map from blocks to the nodes in each block. */ private BlockMap> blockToNodesMap; + private final Map> phantomUsages = new IdentityHashMap<>(); + private final Map> phantomInputs = new IdentityHashMap<>(); public SchedulePhase() { super("Schedule"); @@ -49,12 +141,26 @@ @Override protected void run(StructuredGraph graph) { + SchedulingStrategy strategy = GraalOptions.OptScheduleOutOfLoops ? SchedulingStrategy.LATEST_OUT_OF_LOOPS : SchedulingStrategy.LATEST; + cfg = ControlFlowGraph.compute(graph, true, true, true, false); earliestCache = graph.createNodeMap(); blockToNodesMap = new BlockMap<>(cfg); - assignBlockToNodes(graph); - sortNodesWithinBlocks(graph); + if (GraalOptions.MemoryAwareScheduling && graph.getNodes(FloatingReadNode.class).isNotEmpty()) { + + assignBlockToNodes(graph, SchedulingStrategy.EARLIEST); + sortNodesWithinBlocks(graph, SchedulingStrategy.EARLIEST); + + MemoryScheduleClosure closure = new MemoryScheduleClosure(); + ReentrantBlockIterator.apply(closure, getCFG().getStartBlock(), new HashSet(), null); + + cfg.clearNodeToBlock(); + blockToNodesMap = new BlockMap<>(cfg); + } + + assignBlockToNodes(graph, strategy); + sortNodesWithinBlocks(graph, strategy); } /** @@ -94,7 +200,7 @@ return blockToNodesMap.get(block); } - private void assignBlockToNodes(StructuredGraph graph) { + private void assignBlockToNodes(StructuredGraph graph, SchedulingStrategy strategy) { for (Block block : cfg.getBlocks()) { List nodes = new ArrayList<>(); assert blockToNodesMap.get(block) == null; @@ -106,7 +212,7 @@ for (Node n : graph.getNodes()) { if (n instanceof ScheduledNode) { - assignBlockToNode((ScheduledNode) n); + assignBlockToNode((ScheduledNode) n, strategy); } } } @@ -115,7 +221,7 @@ * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are * already assigned to a block. */ - private void assignBlockToNode(ScheduledNode node) { + private void assignBlockToNode(ScheduledNode node, SchedulingStrategy strategy) { assert !node.isDeleted(); Block prevBlock = cfg.getNodeToBlock().get(node); @@ -126,17 +232,26 @@ // ControlFlowGraph.identifyBlocks assert !(node instanceof PhiNode) : node; assert !(node instanceof FixedNode) : node; - // if in CFG, schedule at the latest position possible in the outermost loop possible - Block latestBlock = latestBlock(node); + Block block; - if (latestBlock == null) { - block = earliestBlock(node); - } else if (GraalOptions.OptScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) { - Block earliestBlock = earliestBlock(node); - block = scheduleOutOfLoops(node, latestBlock, earliestBlock); - assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; - } else { - block = latestBlock; + switch (strategy) { + case EARLIEST: + block = earliestBlock(node); + break; + case LATEST: + case LATEST_OUT_OF_LOOPS: + block = latestBlock(node, strategy); + if (block == null) { + block = earliestBlock(node); + } else if (strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS && !(node instanceof VirtualObjectNode)) { + // schedule at the latest position possible in the outermost loop possible + Block earliestBlock = earliestBlock(node); + block = scheduleOutOfLoops(node, block, earliestBlock); + assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; + } + break; + default: + throw new GraalInternalError("unknown scheduling strategy"); } cfg.getNodeToBlock().set(node, block); blockToNodesMap.get(block).add(node); @@ -145,17 +260,27 @@ /** * 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 */ - private Block latestBlock(ScheduledNode node) { + private Block latestBlock(ScheduledNode node, SchedulingStrategy strategy) { CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); for (Node succ : node.successors().nonNull()) { assert cfg.getNodeToBlock().get(succ) != null; cdbc.apply(cfg.getNodeToBlock().get(succ)); } - ensureScheduledUsages(node); + ensureScheduledUsages(node, strategy); for (Node usage : node.usages()) { - blocksForUsage(node, usage, cdbc); + blocksForUsage(node, usage, cdbc, strategy); } + List usages = phantomUsages.get(node); + if (usages != null) { + for (FixedNode usage : usages) { + assert cfg.getNodeToBlock().get(usage) != null; + cdbc.apply(cfg.getNodeToBlock().get(usage)); + } + } + return cdbc.block; } @@ -204,7 +329,12 @@ assert node.predecessor() == null; for (Node input : node.inputs().nonNull()) { assert input instanceof ValueNode; - Block inputEarliest = earliestBlock(input); + Block inputEarliest; + if (input instanceof InvokeWithExceptionNode) { + inputEarliest = cfg.getNodeToBlock().get(((InvokeWithExceptionNode) input).next()); + } else { + inputEarliest = earliestBlock(input); + } if (!dominators.get(inputEarliest.getId())) { earliest = inputEarliest; do { @@ -242,7 +372,7 @@ * @param usage the usage whose blocks need to be considered * @param closure the closure that will be called for each block */ - private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) { + private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure, SchedulingStrategy strategy) { assert !(node instanceof PhiNode); if (usage instanceof PhiNode) { @@ -274,7 +404,7 @@ 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. - blocksForUsage(node, unscheduledUsage, closure); + blocksForUsage(node, unscheduledUsage, closure, strategy); } else if (unscheduledUsage instanceof MergeNode) { // Only FrameStates can be connected to MergeNodes. assert usage instanceof FrameState; @@ -288,20 +418,20 @@ assert usage instanceof FrameState; assert unscheduledUsage instanceof StateSplit; // Otherwise: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) unscheduledUsage); + assignBlockToNode((ScheduledNode) unscheduledUsage, strategy); closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); } } } else { // All other types of usages: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) usage); + assignBlockToNode((ScheduledNode) usage, strategy); closure.apply(cfg.getNodeToBlock().get(usage)); } } - private void ensureScheduledUsages(Node node) { + private void ensureScheduledUsages(Node node, SchedulingStrategy strategy) { for (Node usage : node.usages().filter(ScheduledNode.class)) { - assignBlockToNode((ScheduledNode) usage); + assignBlockToNode((ScheduledNode) usage, strategy); } // now true usages are ready } @@ -316,27 +446,43 @@ return ControlFlowGraph.commonDominator(a, b); } - private void sortNodesWithinBlocks(StructuredGraph graph) { + private void sortNodesWithinBlocks(StructuredGraph graph, SchedulingStrategy strategy) { NodeBitMap visited = graph.createNodeBitMap(); for (Block b : cfg.getBlocks()) { - sortNodesWithinBlock(b, visited); + sortNodesWithinBlock(b, visited, strategy); } } + private void sortNodesWithinBlock(Block b, NodeBitMap visited, SchedulingStrategy strategy) { + assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; + assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; + + List sortedInstructions; + switch (strategy) { + case EARLIEST: + sortedInstructions = sortNodesWithinBlockEarliest(b, visited); + break; + case LATEST: + case LATEST_OUT_OF_LOOPS: + sortedInstructions = sortNodesWithinBlockLatest(b, visited); + break; + default: + throw new GraalInternalError("unknown scheduling strategy"); + } + blockToNodesMap.put(b, sortedInstructions); + } + /** * 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 void sortNodesWithinBlock(Block b, NodeBitMap visited) { + private List sortNodesWithinBlockLatest(Block b, NodeBitMap visited) { List instructions = blockToNodesMap.get(b); - List sortedInstructions = new ArrayList<>(instructions.size() + 2); - - assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; - assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; + List sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2); for (ScheduledNode i : instructions) { - addToSorting(b, i, sortedInstructions, visited); + addToLatestSorting(b, i, sortedInstructions, visited); } // Make sure that last node gets really last (i.e. when a frame state successor hangs off @@ -363,25 +509,25 @@ sortedInstructions.add(b.getEndNode()); } } - blockToNodesMap.put(b, sortedInstructions); + return sortedInstructions; } - private void addUnscheduledToSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { + private void addUnscheduledToLatestSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { if (state != null) { // UnscheduledNodes should never be marked as visited. assert !visited.isMarked(state); for (Node input : state.inputs()) { if (input instanceof VirtualState) { - addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited); + addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited); } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited); } } } } - private void addToSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { + private void addToLatestSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { return; } @@ -396,17 +542,74 @@ assert state == null; state = (FrameState) input; } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited); + } + } + List inputs = phantomInputs.get(i); + if (inputs != null) { + for (FloatingNode input : inputs) { + addToLatestSorting(b, input, sortedInstructions, visited); } } - addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); + addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); visited.mark(i); - addUnscheduledToSorting(b, state, sortedInstructions, visited); + addUnscheduledToLatestSorting(b, state, sortedInstructions, visited); assert write == null || !visited.isMarked(write); - addToSorting(b, write, sortedInstructions, visited); + addToLatestSorting(b, write, sortedInstructions, visited); // Now predecessors and inputs are scheduled => we can add this node. sortedInstructions.add(i); } + + /** + * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over + * all usages. The resulting list is reversed to create an earliest-possible scheduling of + * nodes. + */ + private List sortNodesWithinBlockEarliest(Block b, NodeBitMap visited) { + List sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2); + addToEarliestSorting(b, b.getEndNode(), sortedInstructions, visited); + Collections.reverse(sortedInstructions); + return sortedInstructions; + } + + private void addToEarliestSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { + if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { + return; + } + + visited.mark(i); + for (Node usage : i.usages()) { + if (usage instanceof VirtualState) { + // only fixed nodes can have VirtualState -> no need to schedule them + } else { + if (i instanceof LoopExitNode && usage instanceof ProxyNode) { + // value proxies should be scheduled before the loopexit, not after + } else { + addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited); + } + } + } + + if (i instanceof BeginNode) { + ArrayList proxies = (i instanceof LoopExitNode) ? new ArrayList() : null; + for (ScheduledNode inBlock : blockToNodesMap.get(b)) { + if (!visited.isMarked(inBlock)) { + if (inBlock instanceof ProxyNode) { + proxies.add((ProxyNode) inBlock); + } else { + addToEarliestSorting(b, inBlock, sortedInstructions, visited); + } + } + } + sortedInstructions.add(i); + if (proxies != null) { + sortedInstructions.addAll(proxies); + } + } else { + sortedInstructions.add(i); + addToEarliestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); + } + } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Fri Mar 01 17:06:08 2013 +0100 @@ -33,6 +33,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.schedule.*; /** * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation @@ -153,13 +154,14 @@ // Save inline context for next dump. previousInlineContext = inlineContext; + final SchedulePhase predefinedSchedule = getPredefinedSchedule(); Debug.sandbox("PrintingGraph", new Runnable() { @Override public void run() { // Finally, output the graph. try { - printer.print(graph, message, null); + printer.print(graph, message, predefinedSchedule); } catch (IOException e) { failuresCount++; printer = null; @@ -191,6 +193,16 @@ return result; } + private static SchedulePhase getPredefinedSchedule() { + SchedulePhase result = null; + for (Object o : Debug.context()) { + if (o instanceof SchedulePhase) { + result = (SchedulePhase) o; + } + } + return result; + } + private void openScope(String name, boolean showThread) { String prefix = showThread ? Thread.currentThread().getName() + ":" : ""; try { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/PointerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/PointerTest.java Fri Mar 01 17:06:08 2013 +0100 @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2013, 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.snippets; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Pointer} read and write operations. + */ +public class PointerTest extends GraalCompilerTest implements SnippetsInterface { + + private static final Object ID = new Object(); + private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; + private final TargetDescription target; + private final SnippetInstaller installer; + + public PointerTest() { + target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new SnippetInstaller(runtime, new Assumptions(false), target); + } + + private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); + return installer.makeGraph(resolvedMethod, inliningPolicy.get()); + } + + @Test + public void test_read1() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_read2() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_read3() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.UNKNOWN_LOCATION); + } + } + + @Test + public void test_write1() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_write2() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_write3() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); + } + } + + private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + ReadNode read = (ReadNode) graph.start().next(); + Assert.assertEquals(kind.getStackKind(), read.kind()); + + UnsafeCastNode cast = (UnsafeCastNode) read.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) read.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + ReturnNode ret = (ReturnNode) read.next(); + Assert.assertEquals(read, ret.result()); + } + + private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + WriteNode write = (WriteNode) graph.start().next(); + Assert.assertEquals(graph.getLocal(2), write.value()); + Assert.assertEquals(Kind.Void, write.kind()); + Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci); + + UnsafeCastNode cast = (UnsafeCastNode) write.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) write.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); + Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci); + + ReturnNode ret = (ReturnNode) stateSplit.next(); + Assert.assertEquals(null, ret.result()); + } + + @Snippet + public static byte readByte1(Object o, int offset) { + return Word.fromObject(o).readByte(offset, ID); + } + + @Snippet + public static byte readByte2(Object o, int offset) { + return Word.fromObject(o).readByte(Word.signed(offset), ID); + } + + @Snippet + public static byte readByte3(Object o, int offset) { + return Word.fromObject(o).readByte(offset); + } + + @Snippet + public static void writeByte1(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value, ID); + } + + @Snippet + public static void writeByte2(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeByte3(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value); + } + + @Snippet + public static char readChar1(Object o, int offset) { + return Word.fromObject(o).readChar(offset, ID); + } + + @Snippet + public static char readChar2(Object o, int offset) { + return Word.fromObject(o).readChar(Word.signed(offset), ID); + } + + @Snippet + public static char readChar3(Object o, int offset) { + return Word.fromObject(o).readChar(offset); + } + + @Snippet + public static void writeChar1(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value, ID); + } + + @Snippet + public static void writeChar2(Object o, int offset, char value) { + Word.fromObject(o).writeChar(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeChar3(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value); + } + + @Snippet + public static short readShort1(Object o, int offset) { + return Word.fromObject(o).readShort(offset, ID); + } + + @Snippet + public static short readShort2(Object o, int offset) { + return Word.fromObject(o).readShort(Word.signed(offset), ID); + } + + @Snippet + public static short readShort3(Object o, int offset) { + return Word.fromObject(o).readShort(offset); + } + + @Snippet + public static void writeShort1(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value, ID); + } + + @Snippet + public static void writeShort2(Object o, int offset, short value) { + Word.fromObject(o).writeShort(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeShort3(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value); + } + + @Snippet + public static int readInt1(Object o, int offset) { + return Word.fromObject(o).readInt(offset, ID); + } + + @Snippet + public static int readInt2(Object o, int offset) { + return Word.fromObject(o).readInt(Word.signed(offset), ID); + } + + @Snippet + public static int readInt3(Object o, int offset) { + return Word.fromObject(o).readInt(offset); + } + + @Snippet + public static void writeInt1(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value, ID); + } + + @Snippet + public static void writeInt2(Object o, int offset, int value) { + Word.fromObject(o).writeInt(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeInt3(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value); + } + + @Snippet + public static long readLong1(Object o, int offset) { + return Word.fromObject(o).readLong(offset, ID); + } + + @Snippet + public static long readLong2(Object o, int offset) { + return Word.fromObject(o).readLong(Word.signed(offset), ID); + } + + @Snippet + public static long readLong3(Object o, int offset) { + return Word.fromObject(o).readLong(offset); + } + + @Snippet + public static void writeLong1(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value, ID); + } + + @Snippet + public static void writeLong2(Object o, int offset, long value) { + Word.fromObject(o).writeLong(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeLong3(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value); + } + + @Snippet + public static float readFloat1(Object o, int offset) { + return Word.fromObject(o).readFloat(offset, ID); + } + + @Snippet + public static float readFloat2(Object o, int offset) { + return Word.fromObject(o).readFloat(Word.signed(offset), ID); + } + + @Snippet + public static float readFloat3(Object o, int offset) { + return Word.fromObject(o).readFloat(offset); + } + + @Snippet + public static void writeFloat1(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value, ID); + } + + @Snippet + public static void writeFloat2(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeFloat3(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value); + } + + @Snippet + public static double readDouble1(Object o, int offset) { + return Word.fromObject(o).readDouble(offset, ID); + } + + @Snippet + public static double readDouble2(Object o, int offset) { + return Word.fromObject(o).readDouble(Word.signed(offset), ID); + } + + @Snippet + public static double readDouble3(Object o, int offset) { + return Word.fromObject(o).readDouble(offset); + } + + @Snippet + public static void writeDouble1(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value, ID); + } + + @Snippet + public static void writeDouble2(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeDouble3(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value); + } + + @Snippet + public static Object readObject1(Object o, int offset) { + return Word.fromObject(o).readObject(offset, ID); + } + + @Snippet + public static Object readObject2(Object o, int offset) { + return Word.fromObject(o).readObject(Word.signed(offset), ID); + } + + @Snippet + public static Object readObject3(Object o, int offset) { + return Word.fromObject(o).readObject(offset); + } + + @Snippet + public static void writeObject1(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value, ID); + } + + @Snippet + public static void writeObject2(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeObject3(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value); + } + +} diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Fri Mar 01 17:06:08 2013 +0100 @@ -51,7 +51,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get(), false); + return installer.makeGraph(resolvedMethod, inliningPolicy.get()); } @Test diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java Fri Mar 01 17:06:08 2013 +0100 @@ -223,11 +223,15 @@ usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue)); } + private boolean usageFollowsInstantiation() { + return instantiation.result != null && instantiation.result.merge().next() == usage; + } + @Override public void replace(ValueNode oldNode, ValueNode newNode) { assert newNode instanceof PhiNode; assert oldNode == instanceOf; - if (sameBlock && solitaryUsage) { + if (sameBlock && solitaryUsage && usageFollowsInstantiation()) { removeIntermediateMaterialization(newNode); } else { newNode.inferStamp(); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -22,30 +22,98 @@ */ package com.oracle.graal.snippets; -import com.oracle.graal.graph.*; +import java.util.*; + import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; /** * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a * snippet. + * + * The frame states of side-effecting nodes are replaced with + * {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid} frame states. Loops that contain invalid + * frame states are also assigned an invalid frame state. + * + * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. */ public class SnippetFrameStateCleanupPhase extends Phase { @Override protected void run(StructuredGraph graph) { - for (Node node : graph.getNodes().filterInterface(StateSplit.class)) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (!stateSplit.hasSideEffect()) { + ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null); + } + + private static class CleanupState { + + public boolean containsFrameState; + + public CleanupState(boolean containsFrameState) { + this.containsFrameState = containsFrameState; + } + } + + /** + * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid + * frame states, so that they can be marked with an invalid frame state. + */ + private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure { + + @Override + protected void processNode(FixedNode node, CleanupState currentState) { + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); if (frameState != null) { - stateSplit.setStateAfter(null); + if (stateSplit.hasSideEffect()) { + currentState.containsFrameState = true; + stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } else { + stateSplit.setStateAfter(null); + } if (frameState.usages().isEmpty()) { GraphUtil.killWithUnusedFloatingInputs(frameState); } } } } + + @Override + protected CleanupState merge(MergeNode merge, List states) { + for (CleanupState state : states) { + if (state.containsFrameState) { + return new CleanupState(true); + } + } + return new CleanupState(false); + } + + @Override + protected CleanupState afterSplit(BeginNode node, CleanupState oldState) { + return new CleanupState(oldState.containsFrameState); + } + + @Override + protected Map processLoop(LoopBeginNode loop, CleanupState initialState) { + LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false)); + boolean containsFrameState = false; + for (CleanupState state : info.endStates.values()) { + containsFrameState |= state.containsFrameState; + } + if (containsFrameState) { + loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } + if (containsFrameState || initialState.containsFrameState) { + for (CleanupState state : info.exitStates.values()) { + state.containsFrameState = true; + } + } + return info.exitStates; + } + } } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Fri Mar 01 17:06:08 2013 +0100 @@ -89,7 +89,7 @@ } ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); assert snippet.getCompilerStorage().get(Graph.class) == null : method; - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), false); + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); // System.out.println("snippet: " + graph); snippet.getCompilerStorage().put(Graph.class, graph); } @@ -152,9 +152,8 @@ substitute = runtime.lookupJavaMethod(substituteMethod); original = runtime.lookupJavaMethod(originalMethod); try { - // System.out.println("substitution: " + MetaUtil.format("%H.%n(%p)", original) + - // " --> " + MetaUtil.format("%H.%n(%p)", substitute)); - StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute), true); + Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); + StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute)); Object oldValue = original.getCompilerStorage().put(Graph.class, graph); assert oldValue == null; } finally { @@ -192,7 +191,7 @@ } } - public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy, final boolean isSubstitution) { + public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable() { @Override @@ -201,12 +200,8 @@ new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph); - if (isSubstitution && !substituteCallsOriginal) { - // TODO (ds) remove the constraint of only processing substitutions - // once issues with the arraycopy snippets have been resolved - new SnippetFrameStateCleanupPhase().apply(graph); - new DeadCodeEliminationPhase().apply(graph); - } + new SnippetFrameStateCleanupPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); new InsertStateAfterPlaceholderPhase().apply(graph); @@ -221,7 +216,6 @@ StructuredGraph graph = graphCache.get(method); if (graph == null) { graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); - // System.out.println("built " + graph); graphCache.put(method, graph); } return graph; @@ -248,10 +242,6 @@ new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); InliningUtil.inline(invoke, originalGraph, true); - // TODO the inlined frame states still show the call from the substitute to the - // original. - // If this poses a problem, a phase should added to fix up these frame states. - Debug.dump(graph, "after inlining %s", callee); if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase(runtime, assumptions).apply(graph); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -364,7 +364,7 @@ if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { StructuredGraph graph = (StructuredGraph) newInstance.graph(); for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { - for (ValueProxyNode vpn : checkCastNode.usages().filter(ValueProxyNode.class).snapshot()) { + for (ProxyNode vpn : checkCastNode.usages().filter(ProxyNode.class).snapshot()) { graph.replaceFloating(vpn, checkCastNode); } for (Node checkCastUsage : checkCastNode.usages().snapshot()) { diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -45,7 +45,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(gen.makeAddress(readKind, gen.operand(address)), false)); + gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false)); } @NodeIntrinsic diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -48,7 +48,7 @@ @Override public void generate(LIRGeneratorTool gen) { Value v = gen.operand(value); - gen.emitStore(gen.makeAddress(kind, gen.operand(address)), v, false); + gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false); } /* diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java Fri Mar 01 17:06:08 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.common.*; public class MacroNode extends AbstractStateSplit implements Lowerable { @@ -47,14 +48,32 @@ this.returnType = invoke.methodCallTarget().returnType(); } + public int getBci() { + return bci; + } + + public ResolvedJavaMethod getTargetMethod() { + return targetMethod; + } + + @SuppressWarnings("unused") + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + return null; + } + @Override public void lower(LoweringTool tool) { - replaceWithInvoke(); + StructuredGraph snippetGraph = getSnippetGraph(tool); + + InvokeNode invoke = replaceWithInvoke(); + + if (snippetGraph != null) { + InliningUtil.inline(invoke, snippetGraph, false); + } } - public InvokeNode replaceWithInvoke() { + private InvokeNode replaceWithInvoke() { InvokeNode invoke = createInvoke(); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); return invoke; } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Fri Mar 01 17:06:08 2013 +0100 @@ -32,10 +32,9 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.graph.ReentrantBlockIterator.MergeableBlockState; import com.oracle.graal.virtual.nodes.*; -class BlockState extends MergeableBlockState { +class BlockState { private final HashMap objectStates = new HashMap<>(); private final HashMap objectAliases = new HashMap<>(); @@ -70,7 +69,6 @@ return object == null ? null : getObjectState(object); } - @Override public BlockState cloneState() { return new BlockState(this); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 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 Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Fri Mar 01 17:06:08 2013 +0100 @@ -457,9 +457,9 @@ } private void processLoopExit(LoopExitNode exitNode, BlockState initialState, BlockState exitState) { - HashMap proxies = new HashMap<>(); + HashMap proxies = new HashMap<>(); - for (ValueProxyNode proxy : exitNode.proxies()) { + for (ProxyNode proxy : exitNode.proxies()) { ObjectState obj = exitState.getObjectState(proxy.value()); if (obj != null) { proxies.put(obj.virtual, proxy); @@ -473,7 +473,7 @@ ObjectState valueObj = exitState.getObjectState(value); if (valueObj == null) { if ((value instanceof PhiNode && ((PhiNode) value).merge() == exitNode.loopBegin()) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) { - ValueProxyNode proxy = new ValueProxyNode(value, exitNode, PhiType.Value); + ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value); obj.setEntry(i, proxy); effects.addFloatingNode(proxy); } @@ -481,9 +481,9 @@ } } else { if (initialObj == null || initialObj.isVirtual()) { - ValueProxyNode proxy = proxies.get(obj.virtual); + ProxyNode proxy = proxies.get(obj.virtual); if (proxy == null) { - proxy = new ValueProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value); + proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value); effects.addFloatingNode(proxy); } else { effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue()); diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Fri Mar 01 17:06:08 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.word; +import com.oracle.graal.nodes.extended.*; + public interface Pointer extends Unsigned { /** @@ -42,6 +44,438 @@ * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + byte readByte(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + char readChar(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + short readShort(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + int readInt(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + long readLong(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + float readFloat(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + double readDouble(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Word readWord(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Object readObject(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + byte readByte(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + char readChar(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + short readShort(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + int readInt(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + long readLong(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + float readFloat(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + double readDouble(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Word readWord(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Object readObject(int offset, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeByte(WordBase offset, byte val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeChar(WordBase offset, char val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeShort(WordBase offset, short val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeInt(WordBase offset, int val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeLong(WordBase offset, long val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeFloat(WordBase offset, float val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeDouble(WordBase offset, double val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeWord(WordBase offset, WordBase val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeObject(WordBase offset, Object val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeByte(int offset, byte val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeChar(int offset, char val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeShort(int offset, short val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeInt(int offset, int val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeLong(int offset, long val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeFloat(int offset, float val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeDouble(int offset, double val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeWord(int offset, WordBase val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeObject(int offset, Object val, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access * @return the result of the memory access */ byte readByte(WordBase offset); @@ -232,150 +666,6 @@ Object readObject(int offset); /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - byte readFinalByte(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - char readFinalChar(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - short readFinalShort(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - int readFinalInt(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - long readFinalLong(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - float readFinalFloat(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - double readFinalDouble(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - Word readFinalWord(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - Object readFinalObject(WordBase offset); - - /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. *

@@ -412,7 +702,7 @@ * @param offset the signed offset for the memory access * @param val the value to be written to memory */ - void writeShort(WordBase offset, Short val); + void writeShort(WordBase offset, short val); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Fri Mar 01 17:06:08 2013 +0100 @@ -58,7 +58,6 @@ COMPARISON, NOT, READ, - READ_FINAL, WRITE, ZERO, FROM_UNSIGNED, @@ -598,6 +597,218 @@ @Override @Operation(opcode = Opcode.READ) + public byte readByte(WordBase offset, Object locationIdentity) { + return unsafe.getByte(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public char readChar(WordBase offset, Object locationIdentity) { + return unsafe.getChar(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public short readShort(WordBase offset, Object locationIdentity) { + return unsafe.getShort(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public int readInt(WordBase offset, Object locationIdentity) { + return unsafe.getInt(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public long readLong(WordBase offset, Object locationIdentity) { + return unsafe.getLong(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public float readFloat(WordBase offset, Object locationIdentity) { + return unsafe.getFloat(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public double readDouble(WordBase offset, Object locationIdentity) { + return unsafe.getDouble(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public Word readWord(WordBase offset, Object locationIdentity) { + return box(unsafe.getAddress(add((Word) offset).unbox())); + } + + @Override + @Operation(opcode = Opcode.READ) + public native Object readObject(WordBase offset, Object locationIdentity); + + @Override + @Operation(opcode = Opcode.READ) + public byte readByte(int offset, Object locationIdentity) { + return readByte(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public char readChar(int offset, Object locationIdentity) { + return readChar(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public short readShort(int offset, Object locationIdentity) { + return readShort(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public int readInt(int offset, Object locationIdentity) { + return readInt(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public long readLong(int offset, Object locationIdentity) { + return readLong(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public float readFloat(int offset, Object locationIdentity) { + return readFloat(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public double readDouble(int offset, Object locationIdentity) { + return readDouble(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public Word readWord(int offset, Object locationIdentity) { + return readWord(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public Object readObject(int offset, Object locationIdentity) { + return readObject(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeByte(WordBase offset, byte val, Object locationIdentity) { + unsafe.putByte(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeChar(WordBase offset, char val, Object locationIdentity) { + unsafe.putChar(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeShort(WordBase offset, short val, Object locationIdentity) { + unsafe.putShort(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeInt(WordBase offset, int val, Object locationIdentity) { + unsafe.putInt(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeLong(WordBase offset, long val, Object locationIdentity) { + unsafe.putLong(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeFloat(WordBase offset, float val, Object locationIdentity) { + unsafe.putFloat(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeDouble(WordBase offset, double val, Object locationIdentity) { + unsafe.putDouble(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeWord(WordBase offset, WordBase val, Object locationIdentity) { + unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox()); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public native void writeObject(WordBase offset, Object val, Object locationIdentity); + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeByte(int offset, byte val, Object locationIdentity) { + writeByte(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeChar(int offset, char val, Object locationIdentity) { + writeChar(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeShort(int offset, short val, Object locationIdentity) { + writeShort(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeInt(int offset, int val, Object locationIdentity) { + writeInt(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeLong(int offset, long val, Object locationIdentity) { + writeLong(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeFloat(int offset, float val, Object locationIdentity) { + writeFloat(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeDouble(int offset, double val, Object locationIdentity) { + writeDouble(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeWord(int offset, WordBase val, Object locationIdentity) { + writeWord(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeObject(int offset, Object val, Object locationIdentity) { + writeObject(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) public byte readByte(WordBase offset) { return unsafe.getByte(add((Word) offset).unbox()); } @@ -703,60 +914,6 @@ } @Override - @Operation(opcode = Opcode.READ_FINAL) - public byte readFinalByte(WordBase offset) { - return readByte(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public char readFinalChar(WordBase offset) { - return readChar(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public short readFinalShort(WordBase offset) { - return readShort(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public int readFinalInt(WordBase offset) { - return readInt(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public long readFinalLong(WordBase offset) { - return readLong(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public float readFinalFloat(WordBase offset) { - return readFloat(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public double readFinalDouble(WordBase offset) { - return readDouble(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public Word readFinalWord(WordBase offset) { - return readWord(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public Object readFinalObject(WordBase offset) { - return readObject(offset); - } - - @Override @Operation(opcode = Opcode.WRITE) public void writeByte(WordBase offset, byte val) { unsafe.putByte(add((Word) offset).unbox(), val); @@ -770,7 +927,7 @@ @Override @Operation(opcode = Opcode.WRITE) - public void writeShort(WordBase offset, Short val) { + public void writeShort(WordBase offset, short val) { unsafe.putShort(add((Word) offset).unbox(), val); } diff -r 0b48dc5f37c3 -r 8fa2eed07f81 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Fri Mar 01 17:05:14 2013 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Fri Mar 01 17:06:08 2013 +0100 @@ -138,18 +138,17 @@ break; case READ: - assert arguments.size() == 2; - replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, LocationNode.ANY_LOCATION)); - break; - - case READ_FINAL: - assert arguments.size() == 2; - replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, LocationNode.FINAL_LOCATION)); + assert arguments.size() == 2 || arguments.size() == 3; + Kind readKind = asKind(callTargetNode.returnType()); + Object readLocation = arguments.size() == 2 ? LocationNode.UNKNOWN_LOCATION : arguments.get(2).asConstant().asObject(); + replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readKind, readLocation)); break; case WRITE: - assert arguments.size() == 3; - replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, LocationNode.ANY_LOCATION)); + assert arguments.size() == 3 || arguments.size() == 4; + Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass())); + Object writeLocation = arguments.size() == 3 ? LocationNode.ANY_LOCATION : arguments.get(3).asConstant().asObject(); + replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, writeKind, writeLocation)); break; case ZERO: @@ -259,8 +258,8 @@ return op; } - private static ValueNode readOp(StructuredGraph graph, ValueNode base, ValueNode offset, Invoke invoke, Object locationIdentity) { - IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, invoke.node().kind(), 0, offset, graph, 1); + private static ValueNode readOp(StructuredGraph graph, ValueNode base, ValueNode offset, Invoke invoke, Kind readKind, Object locationIdentity) { + IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1); ReadNode read = graph.add(new ReadNode(base, location, invoke.node().stamp())); graph.addBeforeFixed(invoke.node(), read); // The read must not float outside its block otherwise it may float above an explicit zero @@ -269,9 +268,10 @@ return read; } - private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode offset, ValueNode value, Invoke invoke, Object locationIdentity) { - IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, value.kind(), 0, offset, graph, 1); + private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode offset, ValueNode value, Invoke invoke, Kind writeKind, Object locationIdentity) { + IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, writeKind, 0, offset, graph, 1); WriteNode write = graph.add(new WriteNode(base, value, location)); + write.setStateAfter(invoke.stateAfter()); graph.addBeforeFixed(invoke.node(), write); return write; } @@ -324,6 +324,14 @@ return false; } + public Kind asKind(JavaType type) { + if (type instanceof ResolvedJavaType) { + return isWord((ResolvedJavaType) type) ? wordKind : type.getKind(); + } else { + return Kind.Object; + } + } + private void changeToWord(ValueNode valueNode) { if (valueNode.isConstant() && valueNode.asConstant().getKind() == Kind.Object) { WordBase value = (WordBase) valueNode.asConstant().asObject();