Mercurial > hg > graal-compiler
changeset 15439:10023073e858
Merge.
author | Roland Schatz <roland.schatz@oracle.com> |
---|---|
date | Tue, 29 Apr 2014 18:35:10 +0200 |
parents | 105fe5c2160e (diff) 34ae63dda6e8 (current diff) |
children | 2f684eda1938 |
files | graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java |
diffstat | 333 files changed, 11046 insertions(+), 3036 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Tue Apr 29 18:23:17 2014 +0200 +++ b/.hgignore Tue Apr 29 18:35:10 2014 +0200 @@ -87,3 +87,4 @@ agent/build/* agent/make/filelist agent/make/sa17.tar.gz +export.json
--- a/CHANGELOG.md Tue Apr 29 18:23:17 2014 +0200 +++ b/CHANGELOG.md Tue Apr 29 18:35:10 2014 +0200 @@ -8,6 +8,7 @@ * Added graal.version system property to Graal enabled VM builds. * Transitioned to JDK 8 as minimum JDK level for Graal. * Added support for stack introspection. +* New MatchRule facility to convert multiple HIR nodes into specialized LIR * ... ### Truffle
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Tue Apr 29 18:35:10 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,4 +93,9 @@ * Gets a description of the target architecture. */ TargetDescription getTarget(); + + /** + * Create a new speculation log for the target runtime. + */ + SpeculationLog createSpeculationLog(); }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Tue Apr 29 18:35:10 2014 +0200 @@ -432,22 +432,20 @@ private static final long serialVersionUID = 3612943150662354844L; public final Object id; - public final Mark[] references; - public Mark(int pcOffset, Object id, Mark[] references) { + public Mark(int pcOffset, Object id) { super(pcOffset); this.id = id; - this.references = references; } @Override public String toString() { if (id == null) { - return String.format("%d[<mark with %d references>]", pcOffset, references.length); + return String.format("%d[<mar>]", pcOffset); } else if (id instanceof Integer) { - return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, Integer.toHexString((Integer) id)); + return String.format("%d[<mark with id %s>]", pcOffset, Integer.toHexString((Integer) id)); } else { - return String.format("%d[<mark with %d references and id %s>]", pcOffset, references.length, id.toString()); + return String.format("%d[<mark with id %s>]", pcOffset, id.toString()); } } } @@ -635,10 +633,9 @@ * * @param codePos the position in the code that is covered by the handler * @param markId the identifier for this mark - * @param references an array of other marks that this mark references */ - public Mark recordMark(int codePos, Object markId, Mark[] references) { - Mark mark = new Mark(codePos, markId, references); + public Mark recordMark(int codePos, Object markId) { + Mark mark = new Mark(codePos, markId); marks.add(mark); return mark; }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,7 +27,7 @@ public interface StackIntrospection { /** - * Accesses the current stack, returning a collection of {@long InspectedFrame}s that can be + * Accesses the current stack, returning a collection of {@link InspectedFrame}s that can be * used to inspect the stack frames' contents. * * @param initialMethods if this is non-{@code null}, then the stack trace will start at these
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Tue Apr 29 18:35:10 2014 +0200 @@ -40,12 +40,30 @@ } }; + /** + * This is the Value of a node which was matched as part of a complex match. The value isn't + * actually useable but this marks it as having been evaluated. + */ + @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) { + + @Override + public String toString() { + return "INTERIOR_MATCH"; + } + + @Override + public boolean equals(Object other) { + // This class is a singleton + return other != null && getClass() == other.getClass(); + } + }; + private final Kind kind; private final PlatformKind platformKind; /** * Initializes a new value of the specified kind. - * + * * @param platformKind the kind */ protected Value(PlatformKind platformKind) {
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Tue Apr 29 18:35:10 2014 +0200 @@ -556,6 +556,17 @@ } /** + * Emits an atomic_exch_global instruction. + * + * @param result result operand that gets the original contents of the memory location + * @param address the memory location + * @param newValue the new value to write to the memory location + */ + public void emitAtomicExch(Kind accessKind, AllocatableValue result, HSAILAddress address, Value newValue) { + emitString(String.format("atomic_exch_global_b%d %s, %s, %s;", getArgSizeFromKind(accessKind), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(newValue))); + } + + /** * Emits a comment. Useful for debugging purposes. * * @param comment
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAddress.java Tue Apr 29 18:35:10 2014 +0200 @@ -30,11 +30,6 @@ public class SPARCAddress extends AbstractAddress { - /** - * Stack bias for stack and frame pointer loads. - */ - private static final int STACK_BIAS = 0x7ff; - private final Register base; private final Register index; private final int displacement; @@ -42,7 +37,7 @@ /** * Creates an {@link SPARCAddress} with given base register, no scaling and a given * displacement. - * + * * @param base the base register * @param displacement the displacement */ @@ -54,7 +49,7 @@ /** * Creates an {@link SPARCAddress} with given base register, no scaling and a given index. - * + * * @param base the base register * @param index the index register */ @@ -113,7 +108,7 @@ /** * This method adds the stack-bias to the displacement if the base register is either * {@link SPARC#sp} or {@link SPARC#fp}. - * + * * @return Optional additive displacement. */ public int getDisplacement() {
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Tue Apr 29 18:35:10 2014 +0200 @@ -37,7 +37,7 @@ /** * Constructs an assembler for the SPARC architecture. - * + * * @param registerConfig the register configuration used to bind {@link Register#Frame} and * {@link Register#CallerFrame} to physical registers. This value can be null if this * assembler instance will not be used to assemble instructions using these logical @@ -50,7 +50,7 @@ // @formatter:off /** * Instruction format for sethi. - * + * * | 00 | rd | op2 | imm22 | * |31 30|29 25|24 22|21 0| */ @@ -123,7 +123,7 @@ // @formatter:off /** * Instruction format for branches. - * + * * | 00 |a | cond | op2 | disp22 | * |31 30|29|28 25|24 22|21 0| */ @@ -142,7 +142,7 @@ // @formatter:off /** * Instruction format for conditional branches. - * + * * | 00 |a | cond | op2 |cc1|cc0|p | disp19 | * |31 30|29|28 25|24 22|21 |20 |19| 0| */ @@ -330,7 +330,7 @@ // @formatter:off /** * Instruction format for calls. - * + * * | 01 | disp30 | * |31 30|29 0| */ @@ -457,7 +457,7 @@ // @formatter:off /** * Instruction format for Arithmetic, Logical, Moves, Tcc, Prefetch, and Misc. - * + * * | 10 | rd | op3 | rs1 | i| imm_asi | rs2 | * | 10 | rd | op3 | rs1 | i| simm13 | * | 10 | rd | op3 | rs1 | i| x| | rs2 | @@ -594,7 +594,7 @@ // @formatter:off /** * Instruction format for Loads, Stores and Misc. - * + * * | 11 | rd | op3 | rs1 | i| imm_asi | rs2 | * | 11 | rd | op3 | rs1 | i| simm13 | * |31 30|29 25|24 19|18 14|13|12 5|4 0| @@ -749,7 +749,7 @@ // @formatter:off /** * Instruction format for Movcc. - * + * * | 10 | rd | op3 |cc2| cond | i|cc1|cc0| - | rs2 | * | 10 | rd | op3 |cc2| cond | i|cc1|cc0| simm11 | * |31 30|29 25|24 19| 18|17 14|13| 12| 11|10 5|4 0| @@ -1007,7 +1007,7 @@ Wrreg(0x30, "wrreg"), Saved(0x31, "saved"), - Fpop1(0x34, "fpop1"), + Fpop1(0b11_0100, "fpop1"), Fpop2(0x35, "fpop2"), Impdep1(0x36, "impdep1"), Impdep2(0x37, "impdep2"), @@ -1036,14 +1036,14 @@ Ldx(0b001011, "ldx"), Stx(0b001110, "stx"), - Ldf(0x20, "ldf"), + Ldf(0b100000, "ldf"), Ldfsr(0x21, "ldfsr"), Ldaf(0x22, "ldaf"), - Lddf(0x23, "lddf"), - Stf(0x24, "stf"), + Lddf(0b100011, "lddf"), + Stf(0b100100, "stf"), Stfsr(0x25, "stfsr"), Staf(0x26, "staf"), - Stdf(0x27, "stdf"); + Stdf(0b100111, "stdf"); // @formatter:on @@ -1092,9 +1092,9 @@ public enum Opfs { // @formatter:off - Fmovs(0x01, "fmovs"), - Fmovd(0x02, "fmovd"), - Fmovq(0x03, "fmovq"), + Fmovs(0b0_0000_0001, "fmovs"), + Fmovd(0b0_0000_0010, "fmovd"), + Fmovq(0b0_0000_0011, "fmovq"), Fnegs(0x05, "fnegs"), Fnegd(0x06, "fnegd"), Fnegq(0x07, "fnegq"), @@ -2376,6 +2376,20 @@ } } + public static class Fmovs extends Fmt3p { + + public Fmovs(Register src, Register dst) { + super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovs, g0, src, dst); + } + } + + public static class Fmovd extends Fmt3p { + + public Fmovd(Register src, Register dst) { + super(Ops.ArithOp, Op3s.Fpop1, Opfs.Fmovd, g0, src, dst); + } + } + public static class Fmuls extends Fmt3p { public Fmuls(Register src1, Register src2, Register dst) { @@ -3174,6 +3188,20 @@ } } + public static class Stdf extends Fmt11 { + + public Stdf(Register dst, SPARCAddress src) { + super(Op3s.Stdf, src, dst); + } + } + + public static class Stf extends Fmt11 { + + public Stf(Register dst, SPARCAddress src) { + super(Op3s.Stf, src, dst); + } + } + public static class Sth extends Fmt11 { public Sth(Register dst, SPARCAddress addr) {
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Tue Apr 29 18:35:10 2014 +0200 @@ -50,7 +50,7 @@ public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, BaselineFrameStateBuilder> implements BytecodeParserTool { private Backend backend; - protected LIRGenerator gen; + protected LIRGeneratorTool gen; private LIRGenerationResult lirGenRes; private BytecodeLIRBuilder lirBuilder; @SuppressWarnings("unused") private BciBlock[] loopHeaders;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Apr 29 18:35:10 2014 +0200 @@ -263,6 +263,25 @@ } } + public void emitCompareBranchMemory(Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, + double trueLabelProbability) { + boolean mirrored = emitCompareMemory(cmpKind, left, right, state); + Condition finalCondition = mirrored ? cond.mirror() : cond; + switch (left.getKind().getStackKind()) { + case Int: + case Long: + case Object: + append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); + break; + case Float: + case Double: + append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); + break; + default: + throw GraalInternalError.shouldNotReachHere("" + left.getKind()); + } + } + @Override public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability)); @@ -343,6 +362,26 @@ } } + /** + * This method emits the compare against memory instruction, and may reorder the operands. It + * returns true if it did so. + * + * @param b the right operand of the comparison + * @return true if the left and right operands were switched, false otherwise + */ + private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) { + boolean mirrored; + if (LIRValueUtil.isVariable(a)) { + Variable left = load(a); + emitCompareRegMemoryOp(cmpKind, left, b, state); + mirrored = false; + } else { + emitCompareMemoryConOp(cmpKind, b, a, state); + mirrored = true; + } + return mirrored; + } + protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, Value value, LIRFrameState state) { assert kind.getStackKind() == value.getKind().getStackKind(); switch (kind) { @@ -761,6 +800,28 @@ } } + public Variable emitRol(Value a, Value b) { + switch (a.getKind().getStackKind()) { + case Int: + return emitShift(IROL, a, b); + case Long: + return emitShift(LROL, a, b); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + public Variable emitRor(Value a, Value b) { + switch (a.getKind().getStackKind()) { + case Int: + return emitShift(IROR, a, b); + case Long: + return emitShift(LROR, a, b); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + private AllocatableValue emitConvert2RegOp(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) { Variable result = newVariable(kind); append(new Unary2RegOp(op, result, input));
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,495 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.compiler.amd64; - -import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; -import static com.oracle.graal.nodes.ConstantNode.*; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.calc.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; - -public class AMD64MemoryPeephole implements MemoryArithmeticLIRLowerer { - protected final AMD64NodeLIRBuilder gen; - protected List<ValueNode> deferredNodes; - - protected AMD64MemoryPeephole(AMD64NodeLIRBuilder gen) { - this.gen = gen; - } - - public Value setResult(ValueNode x, Value operand) { - return gen.setResult(x, operand); - } - - @Override - public boolean memoryPeephole(Access access, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred) { - this.deferredNodes = deferred; - boolean result = operation.generate(this, access); - if (result) { - Debug.log("merge %s %s with %1s %s %s", access, access.asNode().stamp(), operation, result, access.asNode().graph().method()); - } else { - Debug.log("can't merge %s %s with %1s", access, access.asNode().stamp(), operation); - } - this.deferredNodes = null; - return result; - } - - protected LIRFrameState getState(Access access) { - if (access instanceof DeoptimizingNode) { - return gen.state((DeoptimizingNode) access); - } - return null; - } - - protected Kind getMemoryKind(Access access) { - return (Kind) gen.getLIRGenerator().getPlatformKind(access.asNode().stamp()); - } - - protected AMD64AddressValue makeAddress(Access access) { - return (AMD64AddressValue) access.accessLocation().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(access.object())); - } - - protected Value emitBinaryMemory(AMD64Arithmetic op, boolean commutative, ValueNode x, ValueNode y, Access access) { - ValueNode other = x; - if (uncast(other) == access) { - if (commutative) { - other = y; - } else { - return null; - } - } - ensureEvaluated(other); - return gen.getLIRGenerator().emitBinaryMemory(op, getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(other)), makeAddress(access), getState(access)); - } - - /** - * Constants with multiple users need to be evaluated in the right location so that later users - * can pick up the operand. Make sure that happens when it needs to. - */ - protected void ensureEvaluated(ValueNode node) { - evaluateDeferred(node); - evaluateDeferred(); - } - - protected void evaluateDeferred(ValueNode node) { - // Ensure the other input value has a generated value. - if (ConstantNodeRecordsUsages) { - if (!gen.hasOperand(node)) { - assert node instanceof ConstantNode : node; - ((ConstantNode) node).generate(gen); - } - } - } - - protected void evaluateDeferred() { - if (deferredNodes != null) { - for (ValueNode node : deferredNodes) { - evaluateDeferred(node); - } - } - } - - protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) { - AMD64AddressValue address = makeAddress(access); - LIRFrameState state = getState(access); - evaluateDeferred(); - return gen.getLIRGenerator().emitConvert2MemoryOp(kind, op, address, state); - } - - @Override - public Value emitAddMemory(ValueNode x, ValueNode y, Access access) { - switch (getMemoryKind(access)) { - case Int: - return emitBinaryMemory(IADD, true, x, y, access); - case Long: - return emitBinaryMemory(LADD, true, x, y, access); - case Float: - return emitBinaryMemory(FADD, true, x, y, access); - case Double: - return emitBinaryMemory(DADD, true, x, y, access); - default: - return null; - } - } - - @Override - public Value emitSubMemory(ValueNode x, ValueNode y, Access access) { - switch (getMemoryKind(access)) { - case Int: - return emitBinaryMemory(ISUB, false, x, y, access); - case Long: - return emitBinaryMemory(LSUB, false, x, y, access); - case Float: - return emitBinaryMemory(FSUB, false, x, y, access); - case Double: - return emitBinaryMemory(DSUB, false, x, y, access); - default: - return null; - } - } - - @Override - public Value emitMulMemory(ValueNode x, ValueNode y, Access access) { - switch (getMemoryKind(access)) { - case Int: - return emitBinaryMemory(IMUL, true, x, y, access); - case Long: - return emitBinaryMemory(LMUL, true, x, y, access); - case Float: - return emitBinaryMemory(FMUL, true, x, y, access); - case Double: - return emitBinaryMemory(DMUL, true, x, y, access); - default: - return null; - } - } - - @Override - public Value emitDivMemory(ValueNode x, ValueNode y, Access access) { - return null; - } - - @Override - public Value emitRemMemory(ValueNode x, ValueNode y, Access access) { - return null; - } - - @Override - public Value emitAndMemory(ValueNode x, ValueNode y, Access access) { - Kind kind = getMemoryKind(access); - switch (kind) { - case Int: - return emitBinaryMemory(IAND, true, x, y, access); - case Long: - return emitBinaryMemory(LAND, true, x, y, access); - case Short: { - ValueNode other = selectOtherInput(x, y, access); - Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null; - if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) { - // Convert to unsigned load - ensureEvaluated(other); - return emitZeroExtendMemory(16, 32, access); - } - return null; - } - case Byte: { - if (OptFoldMemory.getValue()) { - return null; - } - ValueNode other = selectOtherInput(x, y, access); - Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null; - if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) { - // Convert to unsigned load - ensureEvaluated(other); - return emitConvert2MemoryOp(Kind.Int, MOV_B2UI, access); - } - return null; - } - - default: - return null; - } - } - - @Override - public Value emitOrMemory(ValueNode x, ValueNode y, Access access) { - switch (getMemoryKind(access)) { - case Int: - return emitBinaryMemory(IOR, true, x, y, access); - case Long: - return emitBinaryMemory(LOR, true, x, y, access); - default: - return null; - } - } - - @Override - public Value emitXorMemory(ValueNode x, ValueNode y, Access access) { - switch (getMemoryKind(access)) { - case Int: - return emitBinaryMemory(IXOR, true, x, y, access); - case Long: - return emitBinaryMemory(LXOR, true, x, y, access); - default: - return null; - } - } - - @Override - public Value emitReinterpretMemory(Stamp stamp, Access access) { - PlatformKind to = gen.getLIRGenerator().getPlatformKind(stamp); - Kind from = getMemoryKind(access); - assert to != from : "should have been eliminated"; - - /* - * Conversions between integer to floating point types require moves between CPU and FPU - * registers. - */ - switch ((Kind) to) { - case Int: - switch (from) { - case Float: - return emitConvert2MemoryOp(to, MOV_F2I, access); - } - break; - case Long: - switch (from) { - case Double: - return emitConvert2MemoryOp(to, MOV_D2L, access); - } - break; - case Float: - switch (from) { - case Int: - return emitConvert2MemoryOp(to, MOV_I2F, access); - } - break; - case Double: - switch (from) { - case Long: - return emitConvert2MemoryOp(to, MOV_L2D, access); - } - break; - } - throw GraalInternalError.shouldNotReachHere(); - } - - @Override - public Value emitFloatConvertMemory(FloatConvert op, Access access) { - switch (op) { - case D2F: - return emitConvert2MemoryOp(Kind.Float, D2F, access); - case D2I: - return emitConvert2MemoryOp(Kind.Int, D2I, access); - case D2L: - return emitConvert2MemoryOp(Kind.Long, D2L, access); - case F2D: - return emitConvert2MemoryOp(Kind.Double, F2D, access); - case F2I: - return emitConvert2MemoryOp(Kind.Int, F2I, access); - case F2L: - return emitConvert2MemoryOp(Kind.Long, F2L, access); - case I2D: - return emitConvert2MemoryOp(Kind.Double, I2D, access); - case I2F: - return emitConvert2MemoryOp(Kind.Float, I2F, access); - case L2D: - return emitConvert2MemoryOp(Kind.Double, L2D, access); - case L2F: - return emitConvert2MemoryOp(Kind.Float, L2F, access); - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - @Override - public Value emitSignExtendMemory(Access access, int fromBits, int toBits) { - assert fromBits <= toBits && toBits <= 64; - if (fromBits == toBits) { - return null; - } else if (toBits > 32) { - // sign extend to 64 bits - switch (fromBits) { - case 8: - return emitConvert2MemoryOp(Kind.Long, B2L, access); - case 16: - return emitConvert2MemoryOp(Kind.Long, S2L, access); - case 32: - return emitConvert2MemoryOp(Kind.Long, I2L, access); - default: - throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); - } - } else { - - // sign extend to 32 bits (smaller values are internally represented as 32 bit values) - switch (fromBits) { - case 8: - return emitConvert2MemoryOp(Kind.Int, B2I, access); - case 16: - return emitConvert2MemoryOp(Kind.Int, S2I, access); - case 32: - return null; - default: - throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); - } - } - } - - @Override - public Value emitNarrowMemory(int resultBits, Access access) { - // TODO - return null; - } - - @Override - public Value emitZeroExtendMemory(int fromBits, int toBits, Access access) { - assert fromBits != toBits; - Kind memoryKind = getMemoryKind(access); - if (memoryKind.getBitCount() != fromBits && !memoryKind.isUnsigned()) { - // The memory being read from is signed and smaller than the result size so - // this is a sign extension to inputBits followed by a zero extension to resultBits - // which can't be expressed in a memory operation. - return null; - } - if (memoryKind == Kind.Short) { - memoryKind = Kind.Char; - } - evaluateDeferred(); - return gen.getLIRGenerator().emitZeroExtendMemory(memoryKind, toBits, makeAddress(access), getState(access)); - } - - public boolean emitIfMemory(IfNode x, Access access) { - return emitBranchMemory(x.condition(), access, gen.getLIRBlock(x.trueSuccessor()), gen.getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); - } - - private boolean emitBranchMemory(LogicNode node, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { - if (node instanceof IsNullNode) { - // can't do anything interesting. - return false; - } else if (node instanceof CompareNode) { - CompareNode compare = (CompareNode) node; - return emitCompareBranchMemory(compare, access, trueSuccessor, falseSuccessor, trueSuccessorProbability); - } else if (node instanceof LogicConstantNode) { - return false; - } else if (node instanceof IntegerTestNode) { - return emitIntegerTestBranchMemory((IntegerTestNode) node, access, trueSuccessor, falseSuccessor, trueSuccessorProbability); - } else { - throw GraalInternalError.unimplemented(node.toString()); - } - } - - public boolean emitCompareBranchMemory(CompareNode compare, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { - return emitCompareBranchMemory(compare.x(), compare.y(), access, compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); - } - - public boolean emitIntegerTestBranchMemory(IntegerTestNode test, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { - return emitIntegerTestBranchMemory(test.x(), test.y(), access, trueSuccessor, falseSuccessor, trueSuccessorProbability); - } - - private boolean emitIntegerTestBranchMemory(ValueNode left, ValueNode right, Access access, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) { - ValueNode other = selectOtherInput(left, right, access); - Kind kind = getMemoryKind(access); - if (other.isConstant()) { - if (kind != kind.getStackKind()) { - return false; - } - Constant constant = other.asConstant(); - if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) { - // Only imm32 as long - return false; - } - ensureEvaluated(other); - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access))); - } else { - evaluateDeferred(); - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), gen.operand(other), getState(access))); - } - - gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); - return true; - } - - /** - * @return the input which is not equal to access, accounting for possible UnsafeCastNodes. - */ - protected ValueNode selectOtherInput(ValueNode left, ValueNode right, Access access) { - assert uncast(left) == access || uncast(right) == access; - return uncast(left) == access ? right : left; - } - - protected ValueNode uncast(ValueNode value) { - if (value instanceof UnsafeCastNode) { - UnsafeCastNode cast = (UnsafeCastNode) value; - return cast.getOriginalNode(); - } - return value; - } - - protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, - double trueLabelProbability) { - ValueNode other = selectOtherInput(left, right, access); - Kind kind = getMemoryKind(access); - boolean mirrored = false; - - if (other.isConstant()) { - Constant constant = other.asConstant(); - if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) { - // Only imm32 as long - return false; - } - if (kind.isNumericFloat()) { - Debug.log("Skipping constant compares for float kinds"); - return false; - } - if (kind == Kind.Object) { - if (!constant.isNull()) { - Debug.log("Skipping constant compares for Object kinds"); - return false; - } - } - ensureEvaluated(other); - gen.getLIRGenerator().emitCompareMemoryConOp(kind, makeAddress(access), constant, getState(access)); - mirrored = uncast(right) == access; - } else { - if (kind == Kind.Object) { - // Can't compare against objects since they require encode/decode - Debug.log("Skipping compares for Object kinds"); - return false; - } - - evaluateDeferred(); - gen.getLIRGenerator().emitCompareRegMemoryOp(kind, gen.operand(other), makeAddress(access), getState(access)); - mirrored = uncast(left) == access; - } - - Condition finalCondition = mirrored ? cond.mirror() : cond; - switch (kind.getStackKind()) { - case Long: - case Int: - case Object: - gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); - return true; - case Float: - case Double: - gen.append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); - return true; - default: - throw GraalInternalError.shouldNotReachHere("" + kind.getStackKind()); - } - } -}
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,34 +23,31 @@ package com.oracle.graal.compiler.amd64; +import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; + 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.compiler.common.*; +import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.match.*; +import com.oracle.graal.debug.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.extended.*; public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { - public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) { + public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) { super(graph, gen); } - protected MemoryArithmeticLIRLowerer memoryPeephole; - - @Override - public MemoryArithmeticLIRLowerer getMemoryLowerer() { - if (memoryPeephole == null) { - // Use the generic one - memoryPeephole = new AMD64MemoryPeephole(this); - } - return memoryPeephole; - } - @Override protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { AllocatableValue targetAddress = AMD64.rax.asValue(); @@ -91,6 +88,525 @@ return false; } + protected LIRFrameState getState(Access access) { + if (access instanceof DeoptimizingNode) { + return state((DeoptimizingNode) access); + } + return null; + } + + protected Kind getMemoryKind(Access access) { + return (Kind) gen.getPlatformKind(access.asNode().stamp()); + } + + protected AMD64AddressValue makeAddress(Access access) { + return (AMD64AddressValue) access.accessLocation().generateAddress(this, gen, operand(access.object())); + } + + protected ValueNode uncast(ValueNode value) { + if (value instanceof UnsafeCastNode) { + UnsafeCastNode cast = (UnsafeCastNode) value; + return cast.getOriginalNode(); + } + return value; + } + + protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) { + Condition cond = compare.condition(); + Kind kind = getMemoryKind(access); + + if (value.isConstant()) { + Constant constant = value.asConstant(); + if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) { + // Only imm32 as long + return null; + } + if (kind.isNumericFloat()) { + Debug.log("Skipping constant compares for float kinds"); + return null; + } + if (kind == Kind.Object) { + if (!constant.isNull()) { + Debug.log("Skipping constant compares for Object kinds"); + return null; + } + } + } else { + if (kind == Kind.Object) { + // Can't compare against objects since they require encode/decode + Debug.log("Skipping compares for Object kinds"); + return null; + } + } + + PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp()); + if (cmpKind instanceof Kind) { + // emitCompareBranchMemory expects the memory on the right, so mirror the condition if + // that's not true. It might be mirrored again the actual compare is emitted but that's + // ok. + Condition finalCondition = uncast(compare.x()) == access ? cond.mirror() : cond; + return new ComplexMatchResult() { + public Value evaluate(NodeLIRBuilder builder) { + LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor()); + LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor()); + boolean unorderedIsTrue = compare.unorderedIsTrue(); + double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor()); + Value other; + if (value.isConstant()) { + other = value.asConstant(); + } else { + other = operand(value); + } + + getLIRGeneratorTool().emitCompareBranchMemory((Kind) cmpKind, other, makeAddress(access), getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, + trueLabelProbability); + return null; + } + }; + } + return null; + + } + + private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) { + LabelRef trueLabel = getLIRBlock(x.trueSuccessor()); + LabelRef falseLabel = getLIRBlock(x.falseSuccessor()); + double trueLabelProbability = x.probability(x.trueSuccessor()); + Kind kind = getMemoryKind(access); + if (value.isConstant()) { + if (kind != kind.getStackKind()) { + return null; + } + Constant constant = value.asConstant(); + if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) { + // Only imm32 as long + return null; + } + return new ComplexMatchResult() { + public Value evaluate(NodeLIRBuilder builder) { + gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; + } + }; + } else { + return new ComplexMatchResult() { + public Value evaluate(NodeLIRBuilder builder) { + gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; + } + }; + } + } + + protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) { + AMD64AddressValue address = makeAddress(access); + LIRFrameState state = getState(access); + return getLIRGeneratorTool().emitConvert2MemoryOp(kind, op, address, state); + } + + private Value emitFloatConvertMemory(FloatConvertNode op, Access access) { + switch (op.getOp()) { + case D2F: + return emitConvert2MemoryOp(Kind.Float, D2F, access); + case D2I: + return emitConvert2MemoryOp(Kind.Int, D2I, access); + case D2L: + return emitConvert2MemoryOp(Kind.Long, D2L, access); + case F2D: + return emitConvert2MemoryOp(Kind.Double, F2D, access); + case F2I: + return emitConvert2MemoryOp(Kind.Int, F2I, access); + case F2L: + return emitConvert2MemoryOp(Kind.Long, F2L, access); + case I2D: + return emitConvert2MemoryOp(Kind.Double, I2D, access); + case I2F: + return emitConvert2MemoryOp(Kind.Float, I2F, access); + case L2D: + return emitConvert2MemoryOp(Kind.Double, L2D, access); + case L2F: + return emitConvert2MemoryOp(Kind.Float, L2F, access); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + Kind kind = null; + AMD64Arithmetic op = null; + if (fromBits == toBits) { + return null; + } else if (toBits > 32) { + kind = Kind.Long; + // sign extend to 64 bits + switch (fromBits) { + case 8: + op = B2L; + break; + case 16: + op = S2L; + break; + case 32: + op = I2L; + break; + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } else { + kind = Kind.Int; + // sign extend to 32 bits (smaller values are internally represented as 32 bit values) + switch (fromBits) { + case 8: + op = B2I; + break; + case 16: + op = S2I; + break; + case 32: + return null; + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } + if (kind != null && op != null) { + Kind localKind = kind; + AMD64Arithmetic localOp = op; + return new ComplexMatchResult() { + public Value evaluate(NodeLIRBuilder builder) { + return emitConvert2MemoryOp(localKind, localOp, access); + } + }; + } + return null; + } + + private Value emitReinterpretMemory(PlatformKind to, Access access) { + Kind from = getMemoryKind(access); + assert to != from : "should have been eliminated"; + + /* + * Conversions between integer to floating point types require moves between CPU and FPU + * registers. + */ + switch ((Kind) to) { + case Int: + switch (from) { + case Float: + return emitConvert2MemoryOp(to, MOV_F2I, access); + } + break; + case Long: + switch (from) { + case Double: + return emitConvert2MemoryOp(to, MOV_D2L, access); + } + break; + case Float: + switch (from) { + case Int: + return emitConvert2MemoryOp(to, MOV_I2F, access); + } + break; + case Double: + switch (from) { + case Long: + return emitConvert2MemoryOp(to, MOV_L2D, access); + } + break; + } + throw GraalInternalError.shouldNotReachHere(); + } + + static Object lock = new Object(); + + private AMD64Arithmetic getOp(ValueNode operation, Access access) { + Kind memoryKind = getMemoryKind(access); + if (operation.getClass() == IntegerAddNode.class) { + switch (memoryKind) { + case Int: + return IADD; + case Long: + return LADD; + } + } else if (operation.getClass() == FloatAddNode.class) { + switch (memoryKind) { + case Float: + return FADD; + case Double: + return DADD; + } + } else if (operation.getClass() == AndNode.class) { + switch (memoryKind) { + case Int: + return IAND; + case Long: + return LAND; + } + } else if (operation.getClass() == OrNode.class) { + switch (memoryKind) { + case Int: + return IOR; + case Long: + return LOR; + } + } else if (operation.getClass() == XorNode.class) { + switch (memoryKind) { + case Int: + return IXOR; + case Long: + return LXOR; + } + } else if (operation.getClass() == IntegerSubNode.class) { + switch (memoryKind) { + case Int: + return ISUB; + case Long: + return LSUB; + } + } else if (operation.getClass() == FloatSubNode.class) { + switch (memoryKind) { + case Float: + return FSUB; + case Double: + return DSUB; + } + } else if (operation.getClass() == IntegerMulNode.class) { + switch (memoryKind) { + case Int: + return IMUL; + case Long: + return LMUL; + } + } else if (operation.getClass() == FloatMulNode.class) { + switch (memoryKind) { + case Float: + return FMUL; + case Double: + return DMUL; + } + } + return null; + } + + @MatchRule("(If (IntegerTest=compare Read=access value))") + @MatchRule("(If (IntegerTest=compare FloatingRead=access value))") + public static class IfIntegerTest extends AMD64MatchGenerator { + IfNode root; + Access access; + ValueNode value; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + return gen.emitIntegerTestBranchMemory(root, value, access); + } + } + + @MatchRule("(If (IntegerEquals=compare value Read=access))") + @MatchRule("(If (IntegerLessThan=compare value Read=access))") + @MatchRule("(If (IntegerBelowThan=compare value Read=access))") + @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))") + @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))") + @MatchRule("(If (IntegerBelowThan=compare value FloatingRead=access))") + @MatchRule("(If (FloatEquals=compare value Read=access))") + @MatchRule("(If (FloatEquals=compare value FloatingRead=access))") + @MatchRule("(If (FloatLessThan=compare value Read=access))") + @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))") + public static class IfCompareMemory extends AMD64MatchGenerator { + IfNode root; + Access access; + ValueNode value; + CompareNode compare; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + return gen.emitCompareBranchMemory(root, compare, value, access); + } + } + + @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))") + public static class RotateLeftConstant extends AMD64MatchGenerator { + LeftShiftNode lshift; + UnsignedRightShiftNode rshift; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) { + return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(lshift.x()), gen.operand(lshift.y())); + } + return null; + } + + } + + @MatchRule("(Or (LeftShift=lshift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))") + public static class RotateRightVariable extends AMD64MatchGenerator { + ValueNode value; + ValueNode shiftAmount; + ConstantNode delta; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { + return builder -> gen.getLIRGeneratorTool().emitRor(gen.operand(value), gen.operand(shiftAmount)); + } + return null; + } + + } + + @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))") + public static class RotateLeftVariable extends AMD64MatchGenerator { + ValueNode value; + ValueNode shiftAmount; + ConstantNode delta; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { + return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(value), gen.operand(shiftAmount)); + } + return null; + } + } + + @MatchRule("(IntegerAdd value Read=access)") + @MatchRule("(IntegerSub value Read=access)") + @MatchRule("(IntegerMul value Read=access)") + @MatchRule("(FloatAdd value Read=access)") + @MatchRule("(FloatSub value Read=access)") + @MatchRule("(FloatMul value Read=access)") + @MatchRule("(Or value Read=access)") + @MatchRule("(Xor value Read=access)") + @MatchRule("(And value Read=access)") + @MatchRule("(IntegerAdd value FloatingRead=access)") + @MatchRule("(IntegerSub value FloatingRead=access)") + @MatchRule("(IntegerMul value FloatingRead=access)") + @MatchRule("(FloatAdd value FloatingRead=access)") + @MatchRule("(FloatSub value FloatingRead=access)") + @MatchRule("(FloatMul value FloatingRead=access)") + @MatchRule("(Or value FloatingRead=access)") + @MatchRule("(Xor value FloatingRead=access)") + @MatchRule("(And value FloatingRead=access)") + public static class BinaryRead extends AMD64MatchGenerator { + BinaryNode root; + Access access; + ValueNode value; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + AMD64Arithmetic op = gen.getOp(root, access); + if (op != null) { + return builder -> gen.getLIRGeneratorTool().emitBinaryMemory(op, gen.getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(value)), gen.makeAddress(access), + gen.getState(access)); + } + return null; + } + } + + @MatchRule("(Write Narrow=narrow value)") + public static class WriteNarrow extends AMD64MatchGenerator { + WriteNode root; + NarrowNode narrow; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + return new ComplexMatchResult() { + @Override + public Value evaluate(NodeLIRBuilder builder) { + PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(root.value().stamp()); + Value address = root.location().generateAddress(builder, gen.getLIRGeneratorTool(), gen.operand(root.object())); + Value v = gen.operand(narrow.getInput()); + gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(root)); + return null; + } + }; + } + } + + @MatchRule("(SignExtend Read=access)") + @MatchRule("(SignExtend FloatingRead=access)") + public static class SignExtend extends AMD64MatchGenerator { + Access access; + SignExtendNode root; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + return gen.emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); + } + } + + static abstract class AMD64MatchGenerator implements MatchGenerator { + public AMD64MatchGenerator() { + } + + public ComplexMatchResult match(NodeLIRBuilder gen) { + return match((AMD64NodeLIRBuilder) gen); + } + + abstract public ComplexMatchResult match(AMD64NodeLIRBuilder gen); + } + + @MatchRule("(ZeroExtend Read=access)") + @MatchRule("(ZeroExtend FloatingRead=access)") + public static class ZeroExtend extends AMD64MatchGenerator { + Access access; + ZeroExtendNode root; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + Kind memoryKind = gen.getMemoryKind(access); + if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) { + /* + * The memory being read from is signed and smaller than the result size so this is + * a sign extension to inputBits followed by a zero extension to resultBits which + * can't be expressed in a memory operation. + */ + return null; + } + return new ComplexMatchResult() { + public Value evaluate(NodeLIRBuilder unused) { + return gen.getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), gen.makeAddress(access), gen.getState(access)); + } + }; + } + } + + @MatchRule("(FloatConvert Read=access)") + @MatchRule("(FloatConvert FloatingRead=access)") + public static class FloatConvert extends AMD64MatchGenerator { + Access access; + FloatConvertNode root; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + return new ComplexMatchResult() { + public Value evaluate(NodeLIRBuilder builder) { + return gen.emitFloatConvertMemory(root, access); + } + }; + } + } + + @MatchRule("(Reinterpret Read=access)") + @MatchRule("(Reinterpret FloatingRead=access)") + public static class Reinterpret extends AMD64MatchGenerator { + Access access; + ReinterpretNode root; + + @Override + public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { + return new ComplexMatchResult() { + public Value evaluate(NodeLIRBuilder builder) { + PlatformKind kind = gen.getLIRGeneratorTool().getPlatformKind(root.stamp()); + return gen.emitReinterpretMemory(kind, access); + } + }; + } + } + @Override public void visitBreakpointNode(BreakpointNode node) { JavaType[] sig = new JavaType[node.arguments().size()]; @@ -108,7 +624,7 @@ } @Override - public AMD64LIRGenerator getLIRGenerator() { + public AMD64LIRGenerator getLIRGeneratorTool() { return (AMD64LIRGenerator) gen; } }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Tue Apr 29 18:35:10 2014 +0200 @@ -187,6 +187,8 @@ // Code generator settings @Option(help = "") + public static final OptionValue<Boolean> FlowSensitiveReduction = new OptionValue<>(false); + @Option(help = "") public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true); @Option(help = "") public static final OptionValue<Boolean> UseProfilingInformation = new OptionValue<>(true); @@ -272,7 +274,9 @@ @Option(help = "") public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true); @Option(help = "Allow backend to emit arithmetic and compares directly against memory.") - public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(true); + public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(false); + @Option(help = "Allow backend to match complex expressions.") + public static final OptionValue<Boolean> MatchExpressions = new OptionValue<>(true); /**
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java Tue Apr 29 18:35:10 2014 +0200 @@ -29,12 +29,11 @@ import com.oracle.graal.compiler.common.spi.*; /** - * Describes the possible values of a {@link ValueNode} that produces an int or long result. + * Describes the possible values of a node that produces an int or long result. * * The description consists of (inclusive) lower and upper bounds and up (may be set) and down * (always set) bit-masks. */ -@SuppressWarnings("javadoc") public class IntegerStamp extends PrimitiveStamp { private final long lowerBound;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,9 +23,8 @@ package com.oracle.graal.compiler.common.type; /** - * Describes the possible values of a {@link ValueNode} that produces a primitive value as result. + * Type describing primitive values. */ -@SuppressWarnings("javadoc") public abstract class PrimitiveStamp extends Stamp { private final int bits;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.compiler.common.spi.*; /** - * A stamp is the basis for a type system over the nodes in a graph. + * A stamp is the basis for a type system. */ public abstract class Stamp { @@ -57,13 +57,12 @@ public abstract PlatformKind getPlatformKind(PlatformKindTool tool); /** - * Returns the union of this stamp and the given stamp. Typically used to create stamps for - * {@link ValuePhiNode}s. + * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi + * nodes. * * @param other The stamp that will enlarge this stamp. * @return The union of this stamp and the given stamp. */ - @SuppressWarnings("javadoc") public abstract Stamp meet(Stamp other); /**
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndAddTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,13 +27,10 @@ import org.junit.*; -import sun.misc.*; - import com.oracle.graal.compiler.hsail.test.infra.*; /** - * Tests {@link AtomicInteger#getAndAdd(int)} which indirectly tests - * {@link Unsafe#compareAndSwapInt(Object, long, int, int)}. + * Tests {@link AtomicInteger#getAndAdd(int)} which tests HSAIL atomic_add codegen. */ public class AtomicIntGetAndAddTest extends GraalKernelTester {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicIntGetAndSetTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,72 @@ +/* + * 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.compiler.hsail.test; + +import java.util.*; +import java.util.concurrent.atomic.*; + +import org.junit.*; + +import com.oracle.graal.compiler.hsail.test.infra.*; + +/** + * Tests {@link AtomicInteger#getAndSet(int)} which tests HSAIL atomic_exch codegen. + */ +public class AtomicIntGetAndSetTest extends GraalKernelTester { + + static final int NUM = 1000; + @Result public int[] outArray = new int[NUM]; + AtomicInteger atomicInt = new AtomicInteger(Integer.MAX_VALUE); + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + outArray[i] = -i; + } + } + + @Override + public void runTest() { + setupArrays(); + + dispatchMethodKernel(NUM); + // to complete the circle, replace the initial get value with that of the last executor + for (int i = 0; i < NUM; i++) { + if (outArray[i] == Integer.MAX_VALUE) { + outArray[i] = atomicInt.get(); + } + } + + // note: the actual order of entries in outArray is not predictable + // thus we sort before we compare results + Arrays.sort(outArray); + } + + public void run(int gid) { + outArray[gid] = atomicInt.getAndSet(gid); + } + + @Test + public void test() { + testGeneratedHsail(); + } +}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndAddTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,13 +27,10 @@ import org.junit.*; -import sun.misc.*; - import com.oracle.graal.compiler.hsail.test.infra.*; /** - * Tests {@link AtomicLong#getAndAdd(long)} which indirectly tests - * {@link Unsafe#compareAndSwapLong(Object, long, long, long)}. + * Tests {@link AtomicLong#getAndAdd(long)} which tests HSAIL atomic_add codegen. */ public class AtomicLongGetAndAddTest extends GraalKernelTester {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicLongGetAndSetTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,72 @@ +/* + * 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.compiler.hsail.test; + +import java.util.*; +import java.util.concurrent.atomic.*; + +import org.junit.*; + +import com.oracle.graal.compiler.hsail.test.infra.*; + +/** + * Tests {@link AtomicLong#getAndSet(long)} which tests HSAIL atomic_exch codegen. + */ +public class AtomicLongGetAndSetTest extends GraalKernelTester { + + static final int NUM = 1000; + @Result public long[] outArray = new long[NUM]; + AtomicLong atomicLong = new AtomicLong(Long.MAX_VALUE); + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + outArray[i] = -i; + } + } + + @Override + public void runTest() { + setupArrays(); + + dispatchMethodKernel(NUM); + // to complete the circle, replace the initial get value with that of the last executor + for (int i = 0; i < NUM; i++) { + if (outArray[i] == Long.MAX_VALUE) { + outArray[i] = atomicLong.get(); + } + } + + // note: the actual order of entries in outArray is not predictable + // thus we sort before we compare results + Arrays.sort(outArray); + } + + public void run(int gid) { + outArray[gid] = atomicLong.getAndSet(gid); + } + + @Test + public void test() { + testGeneratedHsail(); + } +}
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicReferenceGetAndSetTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/AtomicReferenceGetAndSetTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -96,7 +96,6 @@ } @Test - @Ignore public void test() { testGeneratedHsail(); }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -118,9 +118,8 @@ dispatchMethodKernel(size, out, in); } - // Marked to only run on hardware until simulator spill bug is fixed. - @Ignore @Test + @Ignore("until stack slots are supported in deopt") public void test() { testGeneratedHsail(); }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -87,9 +87,8 @@ dispatchMethodKernel(size, out, in); } - // Marked to only run on hardware until simulator spill bug is fixed. - @Ignore @Test + @Ignore("until stack slots are supported in deopt") public void test() { testGeneratedHsail(); }
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NewStringEqualsTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -25,11 +25,11 @@ import static com.oracle.graal.debug.Debug.*; -import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; +import org.junit.*; + +import com.oracle.graal.compiler.hsail.test.infra.*; import com.oracle.graal.debug.*; -import org.junit.Test; - /** * Tests creating a String and calling .equals() on it. */ @@ -64,14 +64,16 @@ } // NYI emitForeignCall charAlignedDisjointArraycopy - @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class) + @Ignore + @Test public void test() { try (DebugConfigScope s = disableIntercept()) { testGeneratedHsail(); } } - @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class) + @Ignore + @Test public void testUsingLambdaMethod() { try (DebugConfigScope s = disableIntercept()) { testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/NonEscapingNewObjWithArrayTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,12 +26,12 @@ import static com.oracle.graal.debug.Debug.*; import static com.oracle.graal.debug.DelegatingDebugConfig.Feature.*; -import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; -import com.oracle.graal.debug.*; +import java.util.*; -import org.junit.Test; +import org.junit.*; -import java.util.Arrays; +import com.oracle.graal.compiler.hsail.test.infra.*; +import com.oracle.graal.debug.*; /** * Tests non-escaping object creation and calling a method on it. @@ -78,14 +78,16 @@ } // NYI emitForeignCall floatArraycopy - @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class) + @Ignore + @Test public void test() { try (DebugConfigScope s = disableIntercept()) { testGeneratedHsail(); } } - @Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class) + @Ignore + @Test public void testUsingLambdaMethod() { try (DebugConfigScope dcs = setConfig(new DelegatingDebugConfig().disable(INTERCEPT))) { testGeneratedHsailUsingLambdaMethod();
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -37,7 +37,7 @@ */ public abstract class HSAILNodeLIRBuilder extends NodeLIRBuilder { - public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) { + public HSAILNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { super(graph, lirGen); }
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -56,7 +56,7 @@ } } - public PTXNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) { + public PTXNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { super(graph, lirGen); }
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,7 +27,9 @@ import static com.oracle.graal.lir.sparc.SPARCArithmetic.*; import static com.oracle.graal.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.sparc.SPARCCompare.*; +import static com.oracle.graal.lir.sparc.SPARCControlFlow.*; import static com.oracle.graal.lir.sparc.SPARCMathIntrinsicOp.IntrinsicOpcode.*; +import static com.oracle.graal.lir.sparc.SPARCMove.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -40,25 +42,6 @@ import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.sparc.*; -import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryCommutative; -import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegConst; -import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegReg; -import com.oracle.graal.lir.sparc.SPARCArithmetic.Op1Stack; -import com.oracle.graal.lir.sparc.SPARCArithmetic.Op2Stack; -import com.oracle.graal.lir.sparc.SPARCArithmetic.RemOp; -import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op; -import com.oracle.graal.lir.sparc.SPARCCompare.CompareOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.BranchOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.FloatCondMoveOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp; -import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp; -import com.oracle.graal.lir.sparc.SPARCMove.MembarOp; -import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp; -import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp; -import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp; import com.oracle.graal.phases.util.*; /** @@ -129,7 +112,7 @@ @Override public void emitData(AllocatableValue dst, byte[] data) { - throw GraalInternalError.unimplemented(); + append(new LoadDataAddressOp(dst, data)); } @Override @@ -156,7 +139,7 @@ indexRegister = Value.ILLEGAL; } else { if (scale != 1) { - Value longIndex = emitSignExtend(index, 32, 64); + Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64); if (CodeUtil.isPowerOf2(scale)) { indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale))); } else { @@ -184,16 +167,20 @@ // If we don't have an index register we can use a displacement, otherwise load the // displacement into a register and add it to the base. if (indexRegister.equals(Value.ILLEGAL)) { - // TODO What if displacement if too big? displacementInt = (int) finalDisp; + assert SPARCAssembler.isSimm13(displacementInt) : displacementInt; } else { displacementInt = 0; if (baseRegister.equals(Value.ILLEGAL)) { baseRegister = load(Constant.forLong(finalDisp)); } else { - Variable longBaseRegister = newVariable(Kind.Long); - emitMove(longBaseRegister, baseRegister); // FIXME get rid of this move - baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp)); + if (finalDisp == 0) { + // Nothing to do. Just use the base register. + } else { + Variable longBaseRegister = newVariable(Kind.Long); + emitMove(longBaseRegister, baseRegister); + baseRegister = emitAdd(longBaseRegister, Constant.forLong(finalDisp)); + } } } @@ -282,15 +269,16 @@ Condition finalCondition = mirrored ? cond.mirror() : cond; Variable result = newVariable(trueValue.getKind()); - switch (left.getKind().getStackKind()) { + Kind kind = left.getKind().getStackKind(); + switch (kind) { case Int: case Long: case Object: - append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue))); + append(new CondMoveOp(kind, result, finalCondition, load(trueValue), loadNonConst(falseValue))); break; case Float: case Double: - append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue))); + append(new FloatCondMoveOp(kind, result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue))); break; default: throw GraalInternalError.shouldNotReachHere("" + left.getKind()); @@ -345,7 +333,8 @@ public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { emitIntegerTest(left, right); Variable result = newVariable(trueValue.getKind()); - append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue))); + Kind kind = left.getKind().getStackKind(); + append(new CondMoveOp(kind, result, Condition.EQ, load(trueValue), loadNonConst(falseValue))); return result; } @@ -811,22 +800,23 @@ return inputVal; } else if (toBits > 32) { // sign extend to 64 bits - if (fromBits == 32) { - return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal)); - } else if (fromBits < 32) { - // TODO implement direct x2L sign extension conversions - Value intVal = emitSignExtend(inputVal, fromBits, 32); - return emitSignExtend(intVal, 32, toBits); - } else { - throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + switch (fromBits) { + case 8: + return emitConvert2Op(Kind.Long, B2L, asAllocatable(inputVal)); + case 16: + return emitConvert2Op(Kind.Long, S2L, asAllocatable(inputVal)); + case 32: + return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal)); + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); } } else { // sign extend to 32 bits (smaller values are internally represented as 32 bit values) switch (fromBits) { case 8: - return emitConvert2Op(Kind.Int, I2B, asAllocatable(inputVal)); + return emitConvert2Op(Kind.Int, B2I, asAllocatable(inputVal)); case 16: - return emitConvert2Op(Kind.Int, I2S, asAllocatable(inputVal)); + return emitConvert2Op(Kind.Int, S2I, asAllocatable(inputVal)); case 32: return inputVal; default:
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -37,7 +37,7 @@ */ public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder { - public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) { + public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { super(graph, lirGen); }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java Tue Apr 29 18:35:10 2014 +0200 @@ -52,7 +52,7 @@ */ public class CheckGraalInvariants extends GraalTest { - @LongTest + @Test public void test() { RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); Providers providers = rt.getHostBackend().getProviders();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,23 +22,16 @@ */ package com.oracle.graal.compiler.test; -import static com.oracle.graal.nodes.ConstantNode.*; -import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*; -import static org.junit.Assert.*; - import org.junit.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -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.*; import com.oracle.graal.phases.tiers.*; /** - * Collection of tests for {@link ConditionalEliminationPhase} including those that triggered bugs - * in this phase. + * Collection of tests for {@link com.oracle.graal.phases.common.ConditionalEliminationPhase} + * including those that triggered bugs in this phase. */ public class ConditionalEliminationTest extends GraalCompilerTest { @@ -88,174 +81,6 @@ } while (true); } - /** - * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast - * caused an enclosing instanceof (for the same object and target type) to be incorrectly - * eliminated. - */ - @Test - public void testReanchoringIssue() { - Entry end = new Entry("end"); - EntryWithNext e1 = new EntryWithNext("e1", end); - EntryWithNext e2 = new EntryWithNext("e2", e1); - - test("search", e2, "e3", new Entry("e4")); - } - - @SuppressWarnings("unused") - public static int testNullnessSnippet(Object a, Object b) { - if (a == null) { - if (a == b) { - if (b == null) { - return 1; - } else { - return -2; - } - } else { - if (b == null) { - return -3; - } else { - return 4; - } - } - } else { - if (a == b) { - if (b == null) { - return -5; - } else { - return 6; - } - } else { - if (b == null) { - return 7; - } else { - return 8; - } - } - } - } - - @Test - public void testNullness() { - test("testNullnessSnippet", null, null); - test("testNullnessSnippet", null, new Object()); - test("testNullnessSnippet", new Object(), null); - test("testNullnessSnippet", new Object(), new Object()); - - StructuredGraph graph = parse("testNullnessSnippet"); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - for (ConstantNode constant : getConstantNodes(graph)) { - if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) { - assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0); - } - } - } - - @SuppressWarnings("unused") - public static int testDisjunctionSnippet(Object a) { - try { - if (a instanceof Integer) { - if (a == null) { - return -1; - } else { - return 2; - } - } else { - return 3; - } - } finally { - field = null; - } - } - - @Test - public void testDisjunction() { - StructuredGraph graph = parse("testDisjunctionSnippet"); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - IfNode ifNode = (IfNode) graph.start().next(); - InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition(); - IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0))); - InstanceOfNode y = instanceOf; - ShortCircuitOrNode disjunction = graph.unique(new ShortCircuitOrNode(x, false, y, false, NOT_FREQUENT_PROBABILITY)); - LogicNegationNode negation = graph.unique(new LogicNegationNode(disjunction)); - ifNode.setCondition(negation); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - for (ConstantNode constant : getConstantNodes(graph)) { - if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) { - assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0); - } - } - } - - public static int testInvokeSnippet(Number n) { - if (n instanceof Integer) { - return n.intValue(); - } else { - return 1; - } - } - - @Test - public void testInvoke() { - test("testInvokeSnippet", new Integer(16)); - StructuredGraph graph = parse("testInvokeSnippet"); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); - - InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first(); - assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind()); - } - - public static void testTypeMergingSnippet(Object o, boolean b) { - if (b) { - if (!(o instanceof Double)) { - return; - } - } else { - if (!(o instanceof Integer)) { - return; - } - } - - /* - * For this test the conditional elimination has to correctly merge the type information it - * has about o, so that it can remove the check on Number. - */ - if (!(o instanceof Number)) { - field = o; - } - } - - @Test - public void testTypeMerging() { - StructuredGraph graph = parse("testTypeMergingSnippet"); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - - assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count()); - } - - public static String testInstanceOfCheckCastSnippet(Object e) { - if (e instanceof Entry) { - return ((Entry) e).name; - } - return null; - } - - @Test - public void testInstanceOfCheckCast() { - StructuredGraph graph = parse("testInstanceOfCheckCastSnippet"); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); - - assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count()); - } - public static int testRedundantComparesSnippet(int[] array) { if (array == null) { return 0; @@ -272,39 +97,17 @@ new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); canonicalizer.apply(graph, context); new FloatingReadPhase().apply(graph); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); + new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context); canonicalizer.apply(graph, context); assertEquals(1, graph.getNodes().filter(GuardNode.class).count()); } - public static int testDuplicateNullChecksSnippet(Object a) { - if (a == null) { - return 2; - } - try { - return ((Integer) a).intValue(); - } catch (ClassCastException e) { - return 0; + public static String testInstanceOfCheckCastSnippet(Object e) { + if (e instanceof Entry) { + return ((Entry) e).name; } - } - - @Test - @Ignore - public void testDuplicateNullChecks() { - // This tests whether explicit null checks properly eliminate later null guards. Currently - // it's failing. - StructuredGraph graph = parse("testDuplicateNullChecksSnippet"); - CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true); - PhaseContext context = new PhaseContext(getProviders(), null); - - new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); - canonicalizer.apply(graph, context); - new FloatingReadPhase().apply(graph); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); - canonicalizer.apply(graph, context); - - assertEquals(1, graph.getNodes().filter(GuardNode.class).count()); + return null; } @Test @@ -317,9 +120,10 @@ new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); canonicalizer.apply(graph, context); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); + new ConditionalEliminationPhase(getMetaAccess()).apply(graph, context); canonicalizer.apply(graph, context); assertEquals(0, graph.getNodes().filter(GuardNode.class).count()); } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSenReduTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,395 @@ +/* + * 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 com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugConfig; +import com.oracle.graal.debug.DebugConfigScope; +import com.oracle.graal.debug.internal.DebugScope; +import com.oracle.graal.graph.Node; +import com.oracle.graal.nodes.calc.ObjectEqualsNode; +import com.oracle.graal.nodes.util.GraphUtil; +import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase; +import org.junit.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; + +import java.util.Iterator; +import java.util.List; + +/** + * Tests whether {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} actually + * performs some graph rewritings that it's supposed to perform. + */ +public class FlowSenReduTest extends GraalCompilerTest { + + /* + * A previous instanceof makes redundant a follow-up checkcast. + */ + public Object redundantCheckCastSnippet(Number o) { + Integer z = null; + if (o instanceof Integer) { + z = (Integer) o; // this CheckCastNode will be removed + } + return z; + } + + static final Integer i7 = new Integer(7); + + @Test + public void redundantCheckCastTest() { + assertEquals(i7, redundantCheckCastSnippet(i7)); + StructuredGraph result = afterFlowSensitiveReduce("redundantCheckCastSnippet"); + nodeCountEquals(result, CheckCastNode.class, 0); + nodeCountEquals(result, InstanceOfNode.class, 1); + } + + @SuppressWarnings("unused") + public boolean redundantInstanceOfSnippet01(Object o) { + if (o != null) { + Integer x = (Integer) o; + return (o instanceof Number); // this InstanceOfNode will be removed + } + return false; + } + + @Test + public void redundantInstanceOfTest01() { + String snippet = "redundantInstanceOfSnippet01"; + assertEquals(true, redundantInstanceOfSnippet01(i7)); + nodeCountEquals(afterFlowSensitiveReduce(snippet), InstanceOfNode.class, 1); + } + + /* + * The combination of (previous) non-null-check and checkcast make redundant an instanceof. + */ + @SuppressWarnings("unused") + public Object redundantInstanceOfSnippet02(Object o) { + Integer x = (Integer) o; + if (o != null) { + if (o instanceof Number) { // this InstanceOfNode will be removed + return o; + } + } + return null; + } + + @Test + public void redundantInstanceOfTest02() { + String snippet = "redundantInstanceOfSnippet02"; + assertEquals(i7, redundantInstanceOfSnippet02(i7)); + int ioAfter = getNodes(afterFlowSensitiveReduce(snippet), InstanceOfNode.class).size(); + assertEquals(ioAfter, 1); + } + + /* + * Once an exact-type has been inferred (due to instanceof final-class) a callsite is + * devirtualized. + */ + public int devirtualizationSnippet(Object x, Object y) { + boolean c = x instanceof Integer; + if (c && x == y) { + Number z = (Number) y; // this CheckCastNode will be removed + return z.intValue(); // devirtualized into InvokeSpecial on Integer.intValue() + } + return 0; + } + + @Test + public void devirtualizationTest() { + String snippet = "devirtualizationSnippet"; + assertEquals(i7, devirtualizationSnippet(i7, i7)); + nodeCountEquals(afterFlowSensitiveReduce(snippet), CheckCastNode.class, 0); + + StructuredGraph graph = afterFlowSensitiveReduce(snippet); + assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count()); + + List<InvokeNode> invokeNodes = getNodes(afterFlowSensitiveReduce(snippet), InvokeNode.class); + assertEquals(1, invokeNodes.size()); + + MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget(); + assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind()); + assertEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString()); + } + + /* + * At the return statement, the returned value has been inferred to have type j.l.Number. The + * instanceof is deemed to always evaluate to false. The interplay with tail-duplication is also + * taken into account (resulting in two return statements, each with "false" as input). + */ + @SuppressWarnings("unused") + public boolean t5Snippet(Object o, boolean b) { + Number z; + if (b) { + z = (Number) o; // tail duplication of return stmt, which becomes "return false" + } else { + z = (Integer) o; // tail duplication of return stmt, which becomes "return false" + } + return o instanceof String; // unreachable + } + + @Test + public void t5a() { + String snippet = "t5Snippet"; + assertEquals(false, t5Snippet(null, true)); + StructuredGraph resultGraph = canonicalize(afterFlowSensitiveReduce(snippet)); + nodeCountEquals(resultGraph, ReturnNode.class, 2); + + List<ReturnNode> returnNodes = getNodes(resultGraph, ReturnNode.class); + Iterator<ReturnNode> iter = returnNodes.iterator(); + + ConstantNode c1 = (ConstantNode) iter.next().result(); + ConstantNode c2 = (ConstantNode) iter.next().result(); + + assertEquals(c1, c2); + assertEquals(0, c1.getValue().asInt()); + } + + @Test + public void t5b() { + String snippet = "t5Snippet"; + StructuredGraph graph = afterFlowSensitiveReduce(snippet); + canonicalize(graph); + nodeCountEquals(graph, InstanceOfNode.class, 2); + } + + public boolean t6Snippet(Object x, Object y) { + if (!(x instanceof String)) { + return false; + } + if (!(y instanceof Number)) { + return false; + } + return x == y; // two known-not-to-conform reference values can't be == + } + + // TODO: two known-not-to-conform reference values can't be == + // but baseCaseObjectEqualsNode doesn't check that as of now. + public void t6() { + String snippet = "t6Snippet"; + // visualize(snippet); + StructuredGraph graph = afterFlowSensitiveReduce(snippet); + canonicalize(graph); + nodeCountEquals(graph, ObjectEqualsNode.class, 0); + } + + /* + * A previous instanceof check causes a follow-up instanceof to be deemed unsatisfiable, + * resulting in constant-substitution at that usage. + */ + public Object t7Snippet(Object o) { + if (o instanceof Number) { + if (o instanceof String) { // condition amounts to false + return o; // made unreachable + } + } + return null; + } + + @Test + public void t7() { + String snippet = "t7Snippet"; + StructuredGraph graph = afterFlowSensitiveReduce(snippet); + graph = dce(canonicalize(graph)); + // TODO how to simplify IfNode(false) + assertEquals(1, getNodes(graph, InstanceOfNode.class).size()); + + List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class); + assertEquals(2, returnNodes.size()); + Iterator<ReturnNode> iter = returnNodes.iterator(); + + ConstantNode c1 = (ConstantNode) iter.next().result(); + ConstantNode c2 = (ConstantNode) iter.next().result(); + + assertEquals(c1, c2); + Assert.assertTrue(c1.getValue().isNull()); + } + + /* + * During FlowSensitiveReduction, an unreachable branch doesn't contribute to the merged state. + * The resulting ("non-polluted") more precise inferred type after the merge allows + * devirtualizing a callsite. + */ + public int devirtualizationSnippet02(Number o) { + if (o instanceof Integer) { + Number z = o; + if (o instanceof Long) { + z = o; + } + /* + * devirtualized into InvokeSpecial on Integer.intValue() ie the inferred-type is not + * polluted with values from the unreachable branch. + */ + return z.intValue(); + } + return 0; + } + + @Test + public void devirtualizationTest02() { + String snippet = "devirtualizationSnippet02"; + StructuredGraph graph = afterFlowSensitiveReduce(snippet); + + assertEquals(1, getNodes(graph, InvokeNode.class).size()); + + List<InvokeNode> invokeNodes = getNodes(graph, InvokeNode.class); + assertEquals(1, invokeNodes.size()); + + MethodCallTargetNode target = (MethodCallTargetNode) invokeNodes.get(0).callTarget(); + assertEquals(MethodCallTargetNode.InvokeKind.Special, target.invokeKind()); + assertEquals("HotSpotMethod<Integer.intValue()>", target.targetMethod().toString()); + } + + /* + * TODO ClassCastException known to fail --- either Deopt or throw ObjectGetClassNode The latter + * might lead to direct jump to EH if present. + */ + @SuppressWarnings("unused") + public int t9Snippet(Object o) { + try { + if (o instanceof Number) { + String s = (String) o; + /* + * make a long story short: replace the above with throw new ClassCastException (ok, + * actual type of o unknown). + */ + return 1; + } + } catch (ClassCastException e) { + return 2; + } + return 3; + } + + /* + * "Partial evaluation" via canonicalization of an expression (in the last return statement) one + * of whose leaf sub-expressions was determined to be constant. + */ + @SuppressWarnings("unused") + public Object partialEvalSnippet01(Object o, boolean b) { + if (o == null) { + return o; // turned into "return null;" + } else { + Number z; + if (b) { + z = (Number) o; + } else { + z = (Integer) o; + } + return o instanceof String ? this : null; // turned into "return null;" + } + } + + @Test + public void partialEvalTest01() { + String snippet = "partialEvalSnippet01"; + + StructuredGraph graph = afterFlowSensitiveReduce(snippet); + canonicalize(graph); + dce(graph); + + List<ReturnNode> returnNodes = getNodes(graph, ReturnNode.class); + assertEquals(2, returnNodes.size()); + Iterator<ReturnNode> iter = returnNodes.iterator(); + + ValueNode c1 = GraphUtil.unproxify(iter.next().result()); + ValueNode c2 = GraphUtil.unproxify(iter.next().result()); + assert !iter.hasNext(); + + Assert.assertTrue(c1.isNullConstant()); + Assert.assertTrue(c2.isNullConstant()); + } + + public static class C { + public int f; + } + + /* + * A previous (assumed successful) instanceof check is reused later on to remove a checkcast. + */ + public void deduplicateInstanceOfSnippet(Object o) { + ((C) o).f = ((C) o).f; // boils down to a single instanceof test + } + + @Test + public void deduplicateInstanceOfTest() { + String snippet = "deduplicateInstanceOfSnippet"; + StructuredGraph graph = afterFlowSensitiveReduce(snippet); + List<InstanceOfNode> ioNodes = getNodes(graph, InstanceOfNode.class); + assertEquals(1, ioNodes.size()); + + } + + // --------------------------------------------- + // ----------------- UTILITIES ----------------- + // --------------------------------------------- + + private PhaseContext getPhaseContext() { + return new PhaseContext(getProviders(), null); + } + + private static StructuredGraph dce(StructuredGraph graph) { + new DeadCodeEliminationPhase().apply(graph); + return graph; + } + + private StructuredGraph canonicalize(StructuredGraph graph) { + new CanonicalizerPhase(true).apply(graph, getPhaseContext()); + return graph; + } + + private StructuredGraph flowSensitiveReduce(StructuredGraph graph) { + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, getPhaseContext()); + return graph; + } + + public static <N extends Node> List<N> getNodes(StructuredGraph graph, Class<N> nodeClass) { + return graph.getNodes().filter(nodeClass).snapshot(); + } + + public <N extends Node> void nodeCountEquals(StructuredGraph graph, Class<N> nodeClass, int expected) { + assertEquals(expected, getNodes(graph, nodeClass).size()); + } + + public StructuredGraph afterFlowSensitiveReduce(String snippet) { + StructuredGraph before = canonicalize(parse(snippet)); + // visualize(before, snippet + "-before"); + StructuredGraph result = flowSensitiveReduce(before); + // visualize(result, snippet + "-after"); + return result; + } + + public StructuredGraph visualize(StructuredGraph graph, String title) { + DebugConfig debugConfig = DebugScope.getConfig(); + DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output()); + try (DebugConfigScope s = Debug.setConfig(fixedConfig)) { + Debug.dump(graph, title); + + return graph; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FlowSensitiveReductionTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,293 @@ +/* + * 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 com.oracle.graal.nodes.ConstantNode.*; +import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*; +import static org.junit.Assert.*; + +import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase; +import org.junit.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +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.*; +import com.oracle.graal.phases.tiers.*; + +/** + * Collection of tests for {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} + * including those that triggered bugs in this phase. + */ +public class FlowSensitiveReductionTest extends GraalCompilerTest { + + public static Object field; + + static class Entry { + + final String name; + + public Entry(String name) { + this.name = name; + } + } + + static class EntryWithNext extends Entry { + + public EntryWithNext(String name, Entry next) { + super(name); + this.next = next; + } + + final Entry next; + } + + public static Entry search(Entry start, String name, Entry alternative) { + Entry current = start; + do { + while (current instanceof EntryWithNext) { + if (name != null && current.name == name) { + current = null; + } else { + Entry next = ((EntryWithNext) current).next; + current = next; + } + } + + if (current != null) { + if (current.name.equals(name)) { + return current; + } + } + if (current == alternative) { + return null; + } + current = alternative; + + } while (true); + } + + /** + * This test presents a code pattern that triggered a bug where a (non-eliminated) checkcast + * caused an enclosing instanceof (for the same object and target type) to be incorrectly + * eliminated. + */ + @Test + public void testReanchoringIssue() { + Entry end = new Entry("end"); + EntryWithNext e1 = new EntryWithNext("e1", end); + EntryWithNext e2 = new EntryWithNext("e2", e1); + + test("search", e2, "e3", new Entry("e4")); + } + + @SuppressWarnings("unused") + public static int testNullnessSnippet(Object a, Object b) { + if (a == null) { + if (a == b) { + if (b == null) { + return 1; + } else { + return -2; + } + } else { + if (b == null) { + return -3; + } else { + return 4; + } + } + } else { + if (a == b) { + if (b == null) { + return -5; + } else { + return 6; + } + } else { + if (b == null) { + return 7; + } else { + return 8; + } + } + } + } + + @Test + public void testNullness() { + test("testNullnessSnippet", null, null); + test("testNullnessSnippet", null, new Object()); + test("testNullnessSnippet", new Object(), null); + test("testNullnessSnippet", new Object(), new Object()); + + StructuredGraph graph = parse("testNullnessSnippet"); + PhaseContext context = new PhaseContext(getProviders(), null); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, context); + for (ConstantNode constant : getConstantNodes(graph)) { + if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) { + assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0); + } + } + } + + @SuppressWarnings("unused") + public static int testDisjunctionSnippet(Object a) { + try { + if (a instanceof Integer) { + if (a == null) { + return -1; + } else { + return 2; + } + } else { + return 3; + } + } finally { + field = null; + } + } + + @Test + public void testDisjunction() { + StructuredGraph graph = parse("testDisjunctionSnippet"); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); + IfNode ifNode = (IfNode) graph.start().next(); + InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition(); + IsNullNode x = graph.unique(new IsNullNode(graph.getParameter(0))); + InstanceOfNode y = instanceOf; + ShortCircuitOrNode disjunction = graph.unique(new ShortCircuitOrNode(x, false, y, false, NOT_FREQUENT_PROBABILITY)); + LogicNegationNode negation = graph.unique(new LogicNegationNode(disjunction)); + ifNode.setCondition(negation); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), null)); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); + for (ConstantNode constant : getConstantNodes(graph)) { + if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) { + assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0); + } + } + } + + public static int testInvokeSnippet(Number n) { + if (n instanceof Integer) { + return n.intValue(); + } else { + return 1; + } + } + + @Test + public void testInvoke() { + test("testInvokeSnippet", new Integer(16)); + StructuredGraph graph = parse("testInvokeSnippet"); + PhaseContext context = new PhaseContext(getProviders(), null); + new CanonicalizerPhase(true).apply(graph, context); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context); + + InvokeNode invoke = graph.getNodes().filter(InvokeNode.class).first(); + assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind()); + } + + public static void testTypeMergingSnippet(Object o, boolean b) { + if (b) { + if (!(o instanceof Double)) { + return; + } + } else { + if (!(o instanceof Integer)) { + return; + } + } + + /* + * For this test the conditional elimination has to correctly merge the type information it + * has about o, so that it can remove the check on Number. + */ + if (!(o instanceof Number)) { + field = o; + } + } + + @Test + public void testTypeMerging() { + StructuredGraph graph = parse("testTypeMergingSnippet"); + PhaseContext context = new PhaseContext(getProviders(), null); + new CanonicalizerPhase(true).apply(graph, context); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); + + assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count()); + } + + public static String testInstanceOfCheckCastSnippet(Object e) { + if (e instanceof Entry) { + return ((Entry) e).name; + } + return null; + } + + @Test + public void testInstanceOfCheckCast() { + StructuredGraph graph = parse("testInstanceOfCheckCastSnippet"); + PhaseContext context = new PhaseContext(getProviders(), null); + new CanonicalizerPhase(true).apply(graph, context); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null)); + + assertEquals(0, graph.getNodes().filter(CheckCastNode.class).count()); + } + + public static int testDuplicateNullChecksSnippet(Object a) { + if (a == null) { + return 2; + } + try { + return ((Integer) a).intValue(); + } catch (ClassCastException e) { + return 0; + } + } + + @Test + @Ignore + public void testDuplicateNullChecks() { + // This tests whether explicit null checks properly eliminate later null guards. Currently + // it's failing. + StructuredGraph graph = parse("testDuplicateNullChecksSnippet"); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true); + PhaseContext context = new PhaseContext(getProviders(), null); + + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + canonicalizer.apply(graph, context); + new FloatingReadPhase().apply(graph); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context); + canonicalizer.apply(graph, context); + + assertEquals(1, graph.getNodes().filter(GuardNode.class).count()); + } + +}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -39,7 +39,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.test.*; /** * Test that infopoints in {@link CompilationResult}s have correctly assigned reasons. @@ -72,7 +71,7 @@ } } - @LongTest + @Test public void lineInfopoints() { final Method method = getMethod("testMethod"); final StructuredGraph graph = parseDebug(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -53,7 +53,7 @@ * 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 { @@ -247,7 +247,7 @@ @Test public void testLoop5() { SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES); - assertEquals(7, schedule.getCFG().getBlocks().length); + assertEquals(10, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, false); assertReadWithinAllReturnBlocks(schedule, false); } @@ -266,7 +266,7 @@ StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); assertEquals(1, graph.getNodes(ReturnNode.class).count()); ReturnNode ret = graph.getNodes(ReturnNode.class).first(); - assertTrue(ret.result() instanceof FloatingReadNode); + assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode); assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); assertReadWithinAllReturnBlocks(schedule, true); } @@ -585,7 +585,7 @@ private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final MemoryScheduling memsched, final SchedulingStrategy schedulingStrategy) { final StructuredGraph graph = parse(snippet); try (Scope d = Debug.scope("FloatingReadTest", graph)) { - try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS)) { + try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) { Assumptions assumptions = new Assumptions(false); HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.compiler.test; +import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase; import org.junit.*; import com.oracle.graal.api.code.*; @@ -167,8 +168,9 @@ StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); Assumptions assumptions = new Assumptions(false); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); - new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + PhaseContext context = new PhaseContext(getProviders(), assumptions); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, context); StructuredGraph referenceGraph = parse(referenceSnippet); assertEquals(referenceGraph, graph); }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,6 +24,7 @@ import java.io.*; +import com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase; import org.junit.*; import com.oracle.graal.api.code.*; @@ -184,7 +185,12 @@ StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); Assumptions assumptions = new Assumptions(false); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); + /* + * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase, + * tail-duplication gets activated thus resulting in a graph with more nodes than the + * reference graph. + */ + new ConditionalEliminationPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions)); new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); // a second canonicalizer is needed to process nested MaterializeNodes new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); @@ -239,7 +245,7 @@ StructuredGraph graph = parse(snippet); Assumptions assumptions = new Assumptions(false); new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); - new ConditionalEliminationPhase(getMetaAccess()).apply(graph); + new FlowSensitiveReductionPhase(getMetaAccess()).apply(graph, new PhaseContext(getProviders(), assumptions)); new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); Debug.dump(graph, "Graph " + snippet); Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.test.*; /** * In the following tests, the usages of local variable "a" are replaced with the integer constant @@ -51,7 +50,7 @@ return f1 + " " + arg1 + " " + arg2 + " " + arg3; } - @LongTest + @Test public void test1() { Method method = getMethod("testMethod"); final StructuredGraph graph = parse(method); @@ -74,7 +73,7 @@ } } - @LongTest + @Test public void test3() { Method method = getMethod("testMethod"); final StructuredGraph graph = parse(method); @@ -88,7 +87,7 @@ } } - @LongTest + @Test public void test4() { Method method = getMethod("testMethodVirtual"); final StructuredGraph graph = parse(method);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -38,7 +38,6 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.test.*; public class InliningTest extends GraalCompilerTest { @@ -73,7 +72,7 @@ assertInlined(getGraph("invokeMethodOnFieldSnippet", false)); } - @LongTest + @Test public void testStaticBindableInliningIP() { assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true))); assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true))); @@ -82,7 +81,7 @@ } @Ignore("would need read elimination/EA before inlining") - @LongTest + @Test public void testDependentStaticBindableInliningIP() { assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", true))); assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFieldSnippet", true))); @@ -180,7 +179,7 @@ assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false)); } - @LongTest + @Test public void testClassHierarchyAnalysisIP() { assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true))); assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true)));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/META-INF/services/javax.annotation.processing.Processor Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,1 @@ +com.oracle.graal.compiler.match.MatchProcessor
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Apr 29 18:35:10 2014 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.compiler.alloc.*; import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -45,6 +44,7 @@ import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; @@ -208,7 +208,7 @@ } } - private static void emitBlock(NodeLIRBuilder nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) { + private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap) { if (lirGenRes.getLIR().getLIRforBlock(b) == null) { for (Block pred : b.getPredecessors()) { if (!b.isLoopHeader() || !pred.isLoopEnd()) { @@ -246,8 +246,8 @@ try (Scope ds = Debug.scope("BackEnd", lir)) { FrameMap frameMap = backend.newFrameMap(registerConfig); LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMap, stub); - LIRGenerator lirGen = backend.newLIRGenerator(cc, lirGenRes); - NodeLIRBuilder nodeLirGen = backend.newNodeLIRGenerator(graph, lirGen); + LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes); + NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen); try (Scope s = Debug.scope("LIRGen", lirGen)) { for (Block b : linearScanOrder) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,10 +27,10 @@ import com.oracle.graal.lir.gen.*; public class BytecodeLIRBuilder { - protected final LIRGenerator gen; + protected final LIRGeneratorTool gen; protected final BytecodeParserTool parser; - public BytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) { + public BytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) { this.gen = gen; this.parser = parser; }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -116,20 +116,33 @@ } protected BytecodeFrame computeFrameForState(FrameState state) { - int numLocals = state.localsSize(); - int numStack = state.stackSize(); - int numLocks = state.locksSize(); + try { + assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI; + assert state.bci != BytecodeFrame.UNKNOWN_BCI; + assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0; + assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0; + assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0; + assert !(state.method().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) || + state.locksSize() > 0; + assert state.verify(); + + int numLocals = state.localsSize(); + int numStack = state.stackSize(); + int numLocks = state.locksSize(); - Value[] values = new Value[numLocals + numStack + numLocks]; - computeLocals(state, numLocals, values); - computeStack(state, numLocals, numStack, values); - computeLocks(state, values); + Value[] values = new Value[numLocals + numStack + numLocks]; + computeLocals(state, numLocals, values); + computeStack(state, numLocals, numStack, values); + computeLocks(state, values); - BytecodeFrame caller = null; - if (state.outerFrameState() != null) { - caller = computeFrameForState(state.outerFrameState()); + BytecodeFrame caller = null; + if (state.outerFrameState() != null) { + caller = computeFrameForState(state.outerFrameState()); + } + return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks); + } catch (GraalInternalError e) { + throw e.addContext("FrameState: ", state); } - return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks); } protected void computeLocals(FrameState state, int numLocals, Value[] values) { @@ -168,39 +181,43 @@ private static final DebugMetric STATE_CONSTANTS = Debug.metric("StateConstants"); protected Value toValue(ValueNode value) { - if (value instanceof VirtualObjectNode) { - VirtualObjectNode obj = (VirtualObjectNode) value; - EscapeObjectState state = objectStates.get(obj); - if (state == null && obj.entryCount() > 0) { - // null states occur for objects with 0 fields - throw new GraalInternalError("no mapping found for virtual object %s", obj); - } - if (state instanceof MaterializedObjectState) { - return toValue(((MaterializedObjectState) state).materializedValue()); - } else { - assert obj.entryCount() == 0 || state instanceof VirtualObjectState; - VirtualObject vobject = virtualObjects.get(value); - if (vobject == null) { - vobject = VirtualObject.get(obj.type(), null, virtualObjects.size()); - virtualObjects.put(obj, vobject); + try { + if (value instanceof VirtualObjectNode) { + VirtualObjectNode obj = (VirtualObjectNode) value; + EscapeObjectState state = objectStates.get(obj); + if (state == null && obj.entryCount() > 0) { + // null states occur for objects with 0 fields + throw new GraalInternalError("no mapping found for virtual object %s", obj); } - STATE_VIRTUAL_OBJECTS.increment(); - return vobject; - } - } else if (value instanceof ConstantNode) { - STATE_CONSTANTS.increment(); - return ((ConstantNode) value).getValue(); + if (state instanceof MaterializedObjectState) { + return toValue(((MaterializedObjectState) state).materializedValue()); + } else { + assert obj.entryCount() == 0 || state instanceof VirtualObjectState; + VirtualObject vobject = virtualObjects.get(value); + if (vobject == null) { + vobject = VirtualObject.get(obj.type(), null, virtualObjects.size()); + virtualObjects.put(obj, vobject); + } + STATE_VIRTUAL_OBJECTS.increment(); + return vobject; + } + } else if (value instanceof ConstantNode) { + STATE_CONSTANTS.increment(); + return ((ConstantNode) value).getValue(); - } else if (value != null) { - STATE_VARIABLES.increment(); - Value operand = nodeOperands.get(value); - assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value; - return operand; + } else if (value != null) { + STATE_VARIABLES.increment(); + Value operand = nodeOperands.get(value); + assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value; + return operand; - } else { - // return a dummy value because real value not needed - STATE_ILLEGALS.increment(); - return Value.ILLEGAL; + } else { + // return a dummy value because real value not needed + STATE_ILLEGALS.increment(); + return Value.ILLEGAL; + } + } catch (GraalInternalError e) { + throw e.addContext("toValue: ", value); } } }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.compiler.gen; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.lir.LIR.*; import static com.oracle.graal.nodes.ConstantNode.*; @@ -35,14 +36,15 @@ import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.target.*; +import com.oracle.graal.compiler.match.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.gen.*; -import com.oracle.graal.lir.gen.LIRGenerator.*; +import com.oracle.graal.lir.gen.LIRGenerator.LoadConstant; +import com.oracle.graal.lir.gen.LIRGenerator.Options; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; @@ -58,15 +60,18 @@ private final NodeMap<Value> nodeOperands; private final DebugInfoBuilder debugInfoBuilder; - protected final LIRGenerator gen; + protected final LIRGeneratorTool gen; private ValueNode currentInstruction; private ValueNode lastInstructionPrinted; // Debugging only - public NodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) { + private Map<Class<? extends ValueNode>, List<MatchStatement>> matchRules; + + public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) { this.gen = gen; this.nodeOperands = graph.createNodeMap(); this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands); + matchRules = MatchRuleRegistry.lookup(getClass()); } @SuppressWarnings("hiding") @@ -153,13 +158,25 @@ @Override public Value setResult(ValueNode x, Value operand) { assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable()); - assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice"; + assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice"; assert operand != null && isLegal(operand) : "operand must be legal"; assert !(x instanceof VirtualObjectNode); nodeOperands.set(x, operand); return operand; } + /** + * Used by the {@link MatchStatement} machinery to override the generation LIR for some + * ValueNodes. + */ + public void setMatchResult(ValueNode x, Value operand) { + assert operand.equals(Value.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; + assert operand instanceof ComplexMatchValue || x.usages().count() == 1 : "interior matches must be single user"; + assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice"; + assert !(x instanceof VirtualObjectNode); + nodeOperands.set(x, operand); + } + public LabelRef getLIRBlock(FixedNode b) { assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph; Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b); @@ -171,7 +188,7 @@ } public final void append(LIRInstruction op) { - if (gen.printIRWithLIR && !TTY.isSuppressed()) { + if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { lastInstructionPrinted = currentInstruction; InstructionPrinter ip = new InstructionPrinter(TTY.out()); @@ -192,34 +209,44 @@ } List<ScheduledNode> nodes = blockMap.get(block); - int instructionsFolded = 0; + + if (MatchExpressions.getValue()) { + // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups + // of instructions + matchComplexExpressions(nodes); + } + for (int i = 0; i < nodes.size(); i++) { Node instr = nodes.get(i); - if (gen.traceLevel >= 3) { + if (Options.TraceLIRGeneratorLevel.getValue() >= 3) { TTY.println("LIRGen for " + instr); } - if (instructionsFolded > 0) { - instructionsFolded--; - continue; - } if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) { // Loading of constants is done lazily by operand() } else if (instr instanceof ValueNode) { ValueNode valueNode = (ValueNode) instr; - if (!hasOperand(valueNode)) { + Value operand = getOperand(valueNode); + if (operand == null) { if (!peephole(valueNode)) { - instructionsFolded = maybeFoldMemory(nodes, i, valueNode); - if (instructionsFolded == 0) { - try { - doRoot((ValueNode) instr); - } catch (GraalInternalError e) { - throw GraalGraphInternalError.transformAndAddContext(e, instr); - } catch (Throwable e) { - throw new GraalGraphInternalError(e).addContext(instr); - } + try { + doRoot((ValueNode) instr); + } catch (GraalInternalError e) { + throw GraalGraphInternalError.transformAndAddContext(e, instr); + } catch (Throwable e) { + throw new GraalGraphInternalError(e).addContext(instr); } } + } else if (Value.INTERIOR_MATCH.equals(operand)) { + // Doesn't need to be evaluated + Debug.log("interior match for %s", valueNode); + } else if (operand instanceof ComplexMatchValue) { + Debug.log("complex match for %s", valueNode); + ComplexMatchValue match = (ComplexMatchValue) operand; + operand = match.evaluate(this); + if (operand != null) { + setResult(valueNode, operand); + } } else { // There can be cases in which the result of an instruction is already set // before by other instructions. @@ -244,156 +271,35 @@ gen.doBlockEnd(block); } - private static final DebugMetric MemoryFoldSuccess = Debug.metric("MemoryFoldSuccess"); - private static final DebugMetric MemoryFoldFailed = Debug.metric("MemoryFoldFailed"); - private static final DebugMetric MemoryFoldFailedNonAdjacent = Debug.metric("MemoryFoldedFailedNonAdjacent"); - private static final DebugMetric MemoryFoldFailedDifferentBlock = Debug.metric("MemoryFoldedFailedDifferentBlock"); - - /** - * Subclass can provide helper to fold memory operations into other operations. - */ - public MemoryArithmeticLIRLowerer getMemoryLowerer() { - return null; - } - - private static final Object LOG_OUTPUT_LOCK = new Object(); - - /** - * Try to find a sequence of Nodes which can be passed to the backend to look for optimized - * instruction sequences using memory. Currently this basically is a read with a single - * arithmetic user followed by an possible if use. This should generalized to more generic - * pattern matching so that it can be more flexibly used. - */ - private int maybeFoldMemory(List<ScheduledNode> nodes, int i, ValueNode access) { - MemoryArithmeticLIRLowerer lowerer = getMemoryLowerer(); - if (lowerer != null && GraalOptions.OptFoldMemory.getValue() && (access instanceof ReadNode || access instanceof FloatingReadNode) && access.usages().count() == 1 && i + 1 < nodes.size()) { - try (Scope s = Debug.scope("MaybeFoldMemory", access)) { - // This is all bit hacky since it's happening on the linearized schedule. This needs - // to be revisited at some point. - - // Uncast the memory operation. - Node use = access.usages().first(); - if (use instanceof UnsafeCastNode && use.usages().count() == 1) { - use = use.usages().first(); - } - - // Find a memory lowerable usage of this operation - if (use instanceof MemoryArithmeticLIRLowerable) { - ValueNode operation = (ValueNode) use; - if (!nodes.contains(operation)) { - Debug.log("node %1s in different block from %1s", access, operation); - MemoryFoldFailedDifferentBlock.increment(); - return 0; + protected void matchComplexExpressions(List<ScheduledNode> nodes) { + if (matchRules != null) { + try (Scope s = Debug.scope("MatchComplexExpressions")) { + // Match the nodes in backwards order to encourage longer matches. + for (int index = nodes.size() - 1; index >= 0; index--) { + ScheduledNode snode = nodes.get(index); + if (!(snode instanceof ValueNode)) { + continue; } - ValueNode firstOperation = operation; - if (operation instanceof LogicNode) { - if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) { - ValueNode ifNode = (ValueNode) operation.usages().first(); - if (!nodes.contains(ifNode)) { - MemoryFoldFailedDifferentBlock.increment(); - Debug.log("if node %1s in different block from %1s", ifNode, operation); - try (Indent indent = Debug.logAndIndent("checking operations")) { - int start = nodes.indexOf(access); - int end = nodes.indexOf(operation); - for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) { - Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); - } - } - return 0; - } else { - operation = ifNode; - } - } - } - if (Debug.isLogEnabled()) { - synchronized (LOG_OUTPUT_LOCK) { // Hack to ensure the output is grouped. - try (Indent indent = Debug.logAndIndent("checking operations")) { - int start = nodes.indexOf(access); - int end = nodes.indexOf(operation); - for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) { - Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); - } + ValueNode node = (ValueNode) snode; + // See if this node is the root of any MatchStatements + List<MatchStatement> statements = matchRules.get(node.getClass()); + if (statements != null) { + for (MatchStatement statement : statements) { + if (statement.generate(this, node, nodes)) { + // Found a match so skip to the next + break; } } } - // Possible lowerable operation in the same block. Check out the dependencies. - int opIndex = nodes.indexOf(operation); - int current = i + 1; - ArrayList<ValueNode> deferred = null; - for (; current < opIndex; current++) { - ScheduledNode node = nodes.get(current); - if (node != firstOperation) { - if (node instanceof LocationNode || node instanceof VirtualObjectNode) { - // nothing to do - continue; - } else if (node instanceof ConstantNode) { - if (deferred == null) { - deferred = new ArrayList<>(2); - } - // These nodes are collected and the backend is expended to - // evaluate them before generating the lowered form. This - // basically works around unfriendly scheduling of values which - // are defined in a block but not used there. - deferred.add((ValueNode) node); - continue; - } else if (node instanceof UnsafeCastNode) { - UnsafeCastNode cast = (UnsafeCastNode) node; - if (cast.getOriginalNode() == access) { - continue; - } - } - - // Unexpected inline node - // Debug.log("unexpected node %1s", node); - break; - } - } - - if (current == opIndex) { - if (lowerer.memoryPeephole((Access) access, (MemoryArithmeticLIRLowerable) operation, deferred)) { - MemoryFoldSuccess.increment(); - // if this operation had multiple access inputs, then previous attempts - // would be marked as failures which is wrong. Try to adjust the - // counters to account for this. - for (Node input : operation.inputs()) { - if (input == access) { - continue; - } - if (input instanceof Access && nodes.contains(input)) { - MemoryFoldFailedNonAdjacent.add(-1); - } - } - if (deferred != null) { - // Ensure deferred nodes were evaluated - for (ValueNode node : deferred) { - assert hasOperand(node); - } - } - return opIndex - i; - } else { - // This isn't true failure, it just means there wasn't match for the - // pattern. Usually that means it's just not supported by the backend. - MemoryFoldFailed.increment(); - return 0; - } - } else { - MemoryFoldFailedNonAdjacent.increment(); - } - } else if (!(use instanceof Access) && !(use instanceof PhiNode) && use.usages().count() == 1) { - // memory usage which isn't considered lowerable. Mostly these are - // uninteresting but it might be worth looking at to ensure that interesting - // nodes are being properly handled. - // Debug.log("usage isn't lowerable %1s", access.usages().first()); } } } - return 0; } protected abstract boolean peephole(ValueNode valueNode); private void doRoot(ValueNode instr) { - if (gen.traceLevel >= 2) { + if (Options.TraceLIRGeneratorLevel.getValue() >= 2) { TTY.println("Emitting LIR for instruction " + instr); } currentInstruction = instr; @@ -407,11 +313,7 @@ if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) { Debug.log("This node has invalid type, we are emitting dead code(?): %s", node); } - if (node instanceof LIRGenLowerable) { - ((LIRGenLowerable) node).generate(this); - } else if (node instanceof LIRGenResLowerable) { - ((LIRGenResLowerable) node).generate(this, gen.getResult()); - } else if (node instanceof LIRLowerable) { + if (node instanceof LIRLowerable) { ((LIRLowerable) node).generate(this); } else if (node instanceof ArithmeticLIRLowerable) { ((ArithmeticLIRLowerable) node).generate(this, gen); @@ -460,7 +362,7 @@ } private void moveToPhi(MergeNode merge, AbstractEndNode pred) { - if (gen.traceLevel >= 1) { + if (Options.TraceLIRGeneratorLevel.getValue() >= 1) { TTY.println("MOVE TO PHI from " + pred + " to " + merge); } PhiResolver resolver = new PhiResolver(gen); @@ -725,11 +627,7 @@ } @Override - public LIRGenerator getLIRGeneratorTool() { - return gen; - } - - public LIRGenerator getLIRGenerator() { + public LIRGeneratorTool getLIRGeneratorTool() { return gen; } }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Tue Apr 29 18:35:10 2014 +0200 @@ -34,18 +34,18 @@ /** * Converts {@link ValuePhiNode} instructions into moves. - * + * * Resolves cycles: - * + * * <pre> - * + * * r1 := r2 becomes temp := r1 * r2 := r1 r1 := r2 * r2 := temp * </pre> - * + * * and orders moves: - * + * * <pre> * r2 := r3 becomes r1 := r2 * r1 := r2 r2 := r3 @@ -104,7 +104,7 @@ } } - private final LIRGenerator gen; + private final LIRGeneratorTool gen; /** * The operand loop header phi for the operand currently being process in {@link #dispose()}. @@ -121,7 +121,7 @@ */ private final HashMap<Value, PhiResolverNode> operandToNodeMap = new HashMap<>(); - public PhiResolver(LIRGenerator gen) { + public PhiResolver(LIRGeneratorTool gen) { this.gen = gen; temp = ILLEGAL; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; + +/* + * A closure that can be evaluated to produce the LIR for some complex match. Using a closure + * allows normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes + * evaluated at the proper time. + */ +public interface ComplexMatchResult { + Value evaluate(NodeLIRBuilder gen); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; + +/** + * A wrapper value for the lazy evaluation of a complex match. There's an intermediate class for the + * closure because Value is serializable which is a hassle for the little inner classes which + * usually occur here. + */ +public class ComplexMatchValue extends Value { + /** + * + */ + private static final long serialVersionUID = -4734670273590368770L; + + final ComplexMatchResult result; + + public ComplexMatchValue(ComplexMatchResult result) { + super(Kind.Illegal); + this.result = result; + } + + public Value evaluate(NodeLIRBuilder builder) { + return result.evaluate(builder); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; + +/** + * Helper class to describe the matchable nodes in the core Graal IR. These could possibly live in + * their respective classes but for simplicity in the {@link MatchProcessor} they are grouped here. + */ +@MatchableNode(shortName = "Constant", value = ConstantNode.class, inputs = 0) +@MatchableNode(shortName = "FloatConvert", value = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(shortName = "FloatSub", value = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(shortName = "FloatingRead", value = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) +@MatchableNode(shortName = "If", value = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class) +@MatchableNode(shortName = "IntegerSub", value = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(shortName = "LeftShift", value = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(shortName = "Narrow", value = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(shortName = "Read", value = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) +@MatchableNode(shortName = "Reinterpret", value = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class) +@MatchableNode(shortName = "SignExtend", value = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(shortName = "UnsignedRightShift", value = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(shortName = "Write", value = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class) +@MatchableNode(shortName = "ZeroExtend", value = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(shortName = "And", value = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "FloatAdd", value = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "FloatEquals", value = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "FloatLessThan", value = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "FloatMul", value = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "IntegerAdd", value = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "IntegerBelowThan", value = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "IntegerEquals", value = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "IntegerLessThan", value = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "IntegerMul", value = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "IntegerTest", value = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "ObjectEquals", value = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "Or", value = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(shortName = "Xor", value = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +public class GraalMatchableNodes { + public static class BinaryNodeAdapter extends MatchNodeAdapter { + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((BinaryNode) node).x(); + } + + @Override + protected ValueNode getSecondInput(ValueNode node) { + return ((BinaryNode) node).y(); + } + } + + public static class WriteNodeAdapter extends MatchNodeAdapter { + + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((WriteNode) node).object(); + } + + @Override + protected ValueNode getSecondInput(ValueNode node) { + return ((WriteNode) node).value(); + } + } + + public static class ConvertNodeAdapter extends MatchNodeAdapter { + + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((ConvertNode) node).getInput(); + } + } + + public static class ReinterpretNodeAdapter extends MatchNodeAdapter { + + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((ReinterpretNode) node).value(); + } + } + + public static class IfNodeAdapter extends MatchNodeAdapter { + + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((IfNode) node).condition(); + } + } + + public static class ReadNodeAdapter extends MatchNodeAdapter { + + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((Access) node).object(); + } + } + + public static class BinaryOpLogicNodeAdapter extends MatchNodeAdapter { + + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((BinaryOpLogicNode) node).x(); + } + + @Override + protected ValueNode getSecondInput(ValueNode node) { + return ((BinaryOpLogicNode) node).y(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.match.MatchPattern.Result; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.virtual.*; + +/** + * Container for state captured during a match. + */ +public class MatchContext { + private final ArrayList<ValueNode> consumed = new ArrayList<>(); + private final List<ScheduledNode> nodes; + private final ValueNode root; + private List<String> names; + private List<Class<? extends ValueNode>> types; + private List<ValueNode> values; + private final MatchStatement rule; + private int startIndex; + private int endIndex; + private final NodeLIRBuilder builder; + + public MatchContext(NodeLIRBuilder builder, MatchStatement rule, ValueNode node, List<ScheduledNode> nodes) { + this.builder = builder; + this.rule = rule; + this.root = node; + this.nodes = nodes; + // The root should be the last index since all the inputs must be scheduled before. + startIndex = endIndex = nodes.indexOf(node); + } + + public ValueNode getRoot() { + return root; + } + + public Result captureNamedValue(String name, Class<? extends ValueNode> type, ValueNode value) { + if (names == null) { + names = new ArrayList<>(2); + values = new ArrayList<>(2); + types = new ArrayList<>(2); + } + int index = names.indexOf(name); + if (index == -1) { + names.add(name); + values.add(value); + types.add(type); + return Result.OK; + } else { + if (values.get(index) != value) { + return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern()); + } + return Result.OK; + } + } + + public Result validate() { + // Ensure that there's no unsafe work in between these operations. + for (int i = startIndex; i <= endIndex; i++) { + ScheduledNode node = getNodes().get(i); + if (node instanceof ConstantNode || node instanceof LocationNode || node instanceof VirtualObjectNode || node instanceof ParameterNode) { + // these can be evaluated lazily so don't worry about them. This should probably be + // captured by some interface that indicates that their generate method is empty. + continue; + } else if (!consumed.contains(node) && node != root) { + // This is too verbose for normal logging. + // Debug.log("unexpected node %s", node); + // for (int j = startIndex; j <= endIndex; j++) { + // ScheduledNode theNode = getNodes().get(j); + // Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" : + // " ", + // theNode.usages().count(), theNode); + // } + return Result.NOT_SAFE(node, rule.getPattern()); + } + } + return Result.OK; + } + + /** + * Transfers the captured value into the MatchGenerator instance. The reflective information + * should really be generated and checking during construction of the MatchStatement but this is + * ok for now. + */ + public void transferState(MatchGenerator generator) { + try { + for (int i = 0; i < names.size(); i++) { + String name = names.get(i); + try { + Field field = generator.getClass().getDeclaredField(name); + field.setAccessible(true); + field.set(generator, values.get(i)); + } catch (NoSuchFieldException e) { + // Doesn't exist so the generator doesn't care about the value. + } + } + } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new GraalInternalError(e); + } + try { + Field field = generator.getClass().getDeclaredField("root"); + field.setAccessible(true); + field.set(generator, getRoot()); + } catch (NoSuchFieldException e) { + // Doesn't exist + } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) { + throw new GraalInternalError(e); + } + } + + public void setResult(ComplexMatchResult result) { + setResult(new ComplexMatchValue(result)); + } + + /** + * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result. + * During final LIR generation it will be evaluated to produce the actual LIR value. + * + * @param result + */ + public void setResult(ComplexMatchValue result) { + Debug.log("matched %s %s", rule.getName(), rule.getPattern()); + // Debug.log("%s", rule.formatMatch(root)); + for (ValueNode node : consumed) { + // All the interior nodes should be skipped during the normal doRoot calls in + // NodeLIRBuilder so mark them as interior matches. The root of the match will get a + // closure which will be evaluated to produce the final LIR. + getBuilder().setMatchResult(node, Value.INTERIOR_MATCH); + } + getBuilder().setMatchResult(root, result); + } + + /** + * Mark a node as consumed by the match. Consumed nodes will never be evaluated. + * + * @return Result.OK if the node can be safely consumed. + */ + public Result consume(ValueNode node) { + if (node.usages().count() != 1) { + return Result.TOO_MANY_USERS(node, rule.getPattern()); + } + + if (getBuilder().hasOperand(node)) { + return Result.ALREADY_USED(node, rule.getPattern()); + } + + int index = getNodes().indexOf(node); + if (index == -1) { + return Result.NOT_IN_BLOCK(node, rule.getPattern()); + } + startIndex = Math.min(startIndex, index); + consumed.add(node); + return Result.OK; + } + + private NodeLIRBuilder getBuilder() { + return builder; + } + + private List<ScheduledNode> getNodes() { + return nodes; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import com.oracle.graal.compiler.gen.*; + +/** + * Code generator for complex match patterns. + */ +public interface MatchGenerator { + /** + * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be + * evaluated during LIR generation to produce the final LIR value. + */ + ComplexMatchResult match(NodeLIRBuilder gen); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import com.oracle.graal.nodes.*; + +/** + * Helper class to visit the matchable inputs of a node in a specified order. This may not be needed + * in the end since this could probably be done using the inputs iterator but it simplifies things + * for the moment. + */ +public class MatchNodeAdapter { + @SuppressWarnings("unused") + protected ValueNode getFirstInput(ValueNode node) { + throw new InternalError(); + } + + @SuppressWarnings("unused") + protected ValueNode getSecondInput(ValueNode node) { + throw new InternalError(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import com.oracle.graal.graph.Node.Verbosity; +import com.oracle.graal.nodes.*; + +/** + * A simple recursive pattern matcher for a DAG of nodes. + */ + +public class MatchPattern { + + enum MatchResultCode { + OK, + WRONG_CLASS, + NAMED_VALUE_MISMATCH, + TOO_MANY_USERS, + NOT_IN_BLOCK, + NOT_SAFE, + ALREADY_USED, + } + + /** + * A descriptive result for match failures. This can be helpful for debugging why a match + * doesn't work as expected. + */ + static class Result { + final MatchResultCode code; + final ScheduledNode node; + final MatchPattern matcher; + + Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) { + this.code = result; + this.node = node; + this.matcher = matcher; + } + + static final Result OK = new Result(MatchResultCode.OK, null, null); + + static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) { + return new Result(MatchResultCode.WRONG_CLASS, node, matcher); + } + + static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) { + return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher); + } + + static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) { + return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher); + } + + static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) { + return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher); + } + + static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) { + return new Result(MatchResultCode.NOT_SAFE, node, matcher); + } + + static Result ALREADY_USED(ValueNode node, MatchPattern matcher) { + return new Result(MatchResultCode.ALREADY_USED, node, matcher); + } + + @Override + public String toString() { + if (code == MatchResultCode.OK) { + return "OK"; + } + return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher; + } + } + + /** + * The expected type of the node. It must match exactly. + */ + private final Class<? extends ValueNode> nodeClass; + /** + * An optional name for this node. A name can occur multiple times in a match and that name must + * always refer to the same node of the match will fail. + */ + private final String name; + /** + * An optional pattern for the first input. + */ + private final MatchPattern first; + /** + * An optional pattern for the second input. + */ + private final MatchPattern second; + /** + * Helper class to visit the inputs. + */ + private final MatchNodeAdapter adapter; + /** + * Can there only be one user of the node. Constant nodes can be matched even if there are other + * users. + */ + private final boolean singleUser; + + public MatchPattern(String name, boolean singleUser) { + this(null, name, null, null, null, singleUser); + } + + public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) { + this(nodeClass, name, null, null, null, singleUser); + } + + public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchNodeAdapter adapter, boolean singleUser) { + this(nodeClass, name, first, null, adapter, singleUser); + } + + public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchNodeAdapter adapter, boolean singleUser) { + this.nodeClass = nodeClass; + this.name = name; + this.singleUser = singleUser; + this.first = first; + this.second = second; + this.adapter = adapter; + } + + Class<? extends ValueNode> nodeClass() { + return nodeClass; + } + + Result match(ValueNode node, MatchContext context) { + return matchTree(node, context, true); + } + + private Result matchTree(ValueNode node, MatchContext context, boolean atRoot) { + Result result = Result.OK; + if (nodeClass != null && node.getClass() != nodeClass) { + return Result.WRONG_CLASS(node, this); + } + if (singleUser && !atRoot) { + result = context.consume(node); + if (result != Result.OK) { + return result; + } + } + + if (name != null) { + result = context.captureNamedValue(name, nodeClass, node); + } + + if (first != null) { + result = first.matchTree(adapter.getFirstInput(node), context, false); + if (result == Result.OK && second != null) { + result = second.matchTree(adapter.getSecondInput(node), context, false); + } + } + + return result; + } + + /** + * For a node starting at root, produce a String showing the inputs that matched against this + * rule. It's assumed that a match has already succeeded against this rule, otherwise the + * printing may produce exceptions. + */ + public String formatMatch(ValueNode root) { + String result = String.format("%s", root); + if (first == null && second == null) { + return result; + } else { + return "(" + result + (first != null ? " " + first.formatMatch(adapter.getFirstInput(root)) : "") + (second != null ? " " + second.formatMatch(adapter.getSecondInput(root)) : "") + ")"; + } + } + + @Override + public String toString() { + if (nodeClass == null) { + return name; + } else { + String pre = first != null || second != null ? "(" : ""; + String post = first != null || second != null ? ")" : ""; + String nodeName = nodeClass.getSimpleName(); + return pre + nodeName + (name != null ? "=\"" + name + "\"" : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,574 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.io.*; +import java.util.*; +import java.util.regex.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.Diagnostic.Kind; +import javax.tools.*; + +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.nodes.*; + +/** + * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is + * generated for each top level class containing at least one such field. These service objects can + * be retrieved as follows: + * + * <pre> + * ServiceLoader<MatchStatementSet> sl = ServiceLoader.loadInstalled(MatchStatementSet.class); + * for (MatchStatementSet rules : sl) { + * ... + * } + * </pre> + */ +@SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode"}) +public class MatchProcessor extends AbstractProcessor { + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private final Set<Element> processedMatchRule = new HashSet<>(); + private final Set<Element> processedMatchableNode = new HashSet<>(); + + private static class RuleParseError extends RuntimeException { + private static final long serialVersionUID = 6456128283609257490L; + + RuleParseError(String message) { + super(message); + } + } + + private class RuleParser { + final String[] tokens; + int current; + + RuleParser(String rule) { + Matcher m = tokenizer.matcher(rule); + List<String> list = new ArrayList<>(); + int end = 0; + while (m.lookingAt()) { + list.add(m.group(1)); + end = m.end(); + m.region(m.end(), m.regionEnd()); + } + if (end != m.regionEnd()) { + throw new RuleParseError("unexpected tokens :" + rule.substring(m.end(), m.regionEnd())); + } + tokens = list.toArray(new String[0]); + } + + String next() { + return tokens[current++]; + } + + String peek() { + return tokens[current]; + } + + boolean done() { + return current == tokens.length; + } + + private MatchDescriptor parseSexp() { + if (peek().equals("(")) { + next(); + MatchDescriptor descriptor = parseType(true); + for (int n = 0; n < descriptor.nodeType.inputs; n++) { + if (peek().equals("(")) { + descriptor.inputs[n] = parseSexp(); + } else { + descriptor.inputs[n] = parseType(false); + } + } + for (int n = 0; n < descriptor.nodeType.inputs; n++) { + if (descriptor.inputs[n] == null) { + throw new RuleParseError("not enough inputs for " + descriptor.name); + } + } + if (peek().equals(")")) { + next(); + return descriptor; + } + } + throw new RuleParseError("didn't swallow sexp at: " + peek()); + } + + private MatchDescriptor parseType(boolean sexp) { + TypeDescriptor type = null; + String name = null; + if (Character.isUpperCase(peek().charAt(0))) { + String token = next(); + type = types.get(token); + if (type == null) { + throw new RuleParseError("unknown node type: " + token); + } + if (peek().equals("=")) { + next(); + name = next(); + } + } else { + name = next(); + type = null; + } + return new MatchDescriptor(type, name, sexp); + } + + ArrayList<String> generateVariants() { + MatchDescriptor descriptor = parseSexp(); + if (!done()) { + throw new RuleParseError("didn't consume all tokens"); + } + return descriptor.generateVariants(); + } + } + + static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*"); + + static class TypeDescriptor { + /** + * The name uses in match expressions to refer to this type. + */ + final String shortName; + /** + * The {@link ValueNode} class represented by this type. + */ + final String nodeClass; + + /** + * The {@link ValueNode} class represented by this type. + */ + final String nodePackage; + + /** + * Expected number of matchable inputs. Should be less <= 2 at the moment. + */ + final int inputs; + + /** + * An adapter class to read the proper matchable inputs of the class. + */ + final String adapter; + + /** + * Should swapped variants of this match be generated. The user of the match is expected to + * compensate for any ordering differences in compare which are commutative but require + * reinterpreting the condition in that case. + */ + final boolean commutative; + + /** + * Can multiple users of this node subsume it. Constants can be swallowed into a match even + * if there are multiple users. + */ + final boolean cloneable; + + TypeDescriptor(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { + this.shortName = shortName; + this.nodeClass = nodeClass; + this.nodePackage = nodePackage; + this.inputs = inputs; + this.adapter = adapter; + this.commutative = commutative; + this.cloneable = (nodePackage + "." + nodeClass).equals(ConstantNode.class.getName()); + assert !commutative || inputs == 2; + } + } + + HashMap<String, TypeDescriptor> types = new HashMap<>(); + ArrayList<String> packages = new ArrayList<>(); + + private void declareType(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { + TypeDescriptor descriptor = new TypeDescriptor(shortName, nodeClass, nodePackage, inputs, adapter, commutative); + types.put(shortName, descriptor); + if (!packages.contains(descriptor.nodePackage)) { + packages.add(descriptor.nodePackage); + } + } + + private static String findPackage(Element type) { + Element enclosing = type.getEnclosingElement(); + while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) { + enclosing = enclosing.getEnclosingElement(); + } + if (enclosing != null && enclosing.getKind() == ElementKind.PACKAGE) { + return ((PackageElement) enclosing).getQualifiedName().toString(); + } + throw new GraalInternalError("can't find package for %s", type); + } + + static class MatchDescriptor { + TypeDescriptor nodeType; + String name; + MatchDescriptor[] inputs; + + MatchDescriptor(TypeDescriptor nodeType, String name, boolean sexp) { + this.nodeType = nodeType; + this.name = name; + if (sexp) { + this.inputs = new MatchDescriptor[nodeType.inputs]; + } else { + this.inputs = new MatchDescriptor[0]; + } + } + + ArrayList<String> generateVariants() { + String prefix = formatPrefix(); + String suffix = formatSuffix(); + ArrayList<String> variants = new ArrayList<>(); + if (inputs.length == 2) { + // Generate this version and a swapped version + for (String first : inputs[0].generateVariants()) { + for (String second : inputs[1].generateVariants()) { + variants.add(prefix + ", " + first + ", " + second + suffix); + if (nodeType.commutative) { + variants.add(prefix + ", " + second + ", " + first + suffix); + } + } + } + } else if (inputs.length == 1) { + for (String first : inputs[0].generateVariants()) { + variants.add(prefix + ", " + first + suffix); + } + } else { + variants.add(prefix + suffix); + } + return variants; + } + + private String formatPrefix() { + if (nodeType == null) { + return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null"); + } else { + return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null"); + } + } + + private String formatSuffix() { + if (nodeType != null) { + if (inputs.length != nodeType.inputs) { + return ", true)"; + } else { + if (nodeType.adapter != null) { + return ", " + nodeType.adapter + "," + !nodeType.cloneable + ")"; + } + if (nodeType.cloneable) { + return ", false)"; + } + } + } + return ")"; + } + + } + + private void createFiles(MatchRuleDescriptor info) { + String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); + Name topDeclaringClass = info.topDeclaringType.getSimpleName(); + + String optionsClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName(); + Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); + + Filer filer = processingEnv.getFiler(); + try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { + + out.println("// CheckStyle: stop header check"); + out.println("// GENERATED CONTENT - DO NOT EDIT"); + out.println("// Source: " + topDeclaringClass + ".java"); + out.println("package " + pkg + ";"); + out.println(""); + out.println("import java.util.*;"); + out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;"); + out.println("import " + NodeLIRBuilder.class.getName() + ";"); + for (String p : packages) { + out.println("import " + p + ".*;"); + } + out.println(""); + out.println("public class " + optionsClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {"); + String desc = MatchStatement.class.getSimpleName(); + out.println(" // CheckStyle: stop line length check"); + out.println(" private static final List<" + desc + "> options = Collections.unmodifiableList(Arrays.asList("); + + int i = 0; + for (MatchRuleItem option : info.options) { + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String name = option.name; + Name fieldName = option.field.getSimpleName(); + String comma = i == info.options.size() - 1 ? "" : ","; + out.printf(" new MatchStatement(\"%s\", %s, %s.class)%s\n", fieldName, name, optionValue, comma); + i++; + } + out.println(" ));"); + out.println(" // CheckStyle: resume line length check"); + out.println(); + + out.println(" public Class<? extends NodeLIRBuilder> forClass() {"); + out.println(" return " + topDeclaringClass + ".class;"); + out.println(" }"); + out.println(); + out.println(" @Override"); + out.println(" public List<" + desc + "> statements() {"); + out.println(" return options;"); + out.println(" }"); + out.println("}"); + } + + try { + createProviderFile(pkg, optionsClassName, originatingElements); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType); + } + } + + private void createProviderFile(String pkg, String providerClassName, Element... originatingElements) throws IOException { + String filename = "META-INF/providers/" + pkg + "." + providerClassName; + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); + writer.println(MatchStatementSet.class.getName()); + writer.close(); + } + + protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { + try { + // Ensure Unix line endings to comply with Graal code style guide checked by Checkstyle + JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements); + return new PrintWriter(sourceFile.openWriter()) { + + @Override + public void println() { + print("\n"); + } + }; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static class MatchRuleItem implements Comparable<MatchRuleItem> { + + final String name; + final String declaringClass; + final TypeElement field; + + public MatchRuleItem(String name, String declaringClass, TypeElement field) { + this.name = name; + this.declaringClass = declaringClass; + this.field = field; + } + + @Override + public int compareTo(MatchRuleItem other) { + return name.compareTo(other.name); + } + + @Override + public String toString() { + return declaringClass + "." + field; + } + } + + static class MatchRuleDescriptor { + + final TypeElement topDeclaringType; + final List<MatchRuleItem> options = new ArrayList<>(); + final Set<Element> originatingElements = new HashSet<>(); + + public MatchRuleDescriptor(TypeElement topDeclaringType) { + this.topDeclaringType = topDeclaringType; + } + } + + private static TypeElement topDeclaringType(Element element) { + Element enclosing = element.getEnclosingElement(); + if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE; + return (TypeElement) element; + } + return topDeclaringType(enclosing); + } + + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + try { + // Import default definitions + processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName())); + for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodeImport.class)) { + // Import any other definitions required by this element + String[] imports = element.getAnnotation(MatchableNodeImport.class).value(); + for (String m : imports) { + TypeElement el = processingEnv.getElementUtils().getTypeElement(m); + processMatchableNode(el); + } + } + + // Process any local MatchableNode declarations + for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) { + processMatchableNode(element); + } + + Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>(); + for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) { + processMatchRule(map, element); + } + for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) { + processMatchRule(map, element); + } + + for (MatchRuleDescriptor info : map.values()) { + createFiles(info); + } + + } catch (Throwable t) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t); + } + + return true; + } + + /** + * Build up the type table to be used during parsing of the MatchRule. + */ + private void processMatchableNode(Element element) { + if (!processedMatchableNode.contains(element)) { + processedMatchableNode.add(element); + TypeElement topDeclaringType = topDeclaringType(element); + MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class); + for (MatchableNode matchable : matchables) { + String nodeClass; + String nodePackage; + String shortName = matchable.shortName(); + TypeMirror nodeClassMirror = null; + try { + matchable.value(); + } catch (MirroredTypeException e) { + nodeClassMirror = e.getTypeMirror(); + } + if (nodeClassMirror == null) { + throw new GraalInternalError("Can't get mirror for node class %s", element); + } + if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) { + nodeClass = topDeclaringType.getQualifiedName().toString(); + } else { + nodeClass = nodeClassMirror.toString(); + } + nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass)); + assert nodeClass.startsWith(nodePackage); + nodeClass = nodeClass.substring(nodePackage.length() + 1); + + TypeMirror nodeAdapterMirror = null; + try { + matchable.adapter(); + } catch (MirroredTypeException e) { + nodeAdapterMirror = e.getTypeMirror(); + } + if (nodeAdapterMirror == null) { + throw new GraalInternalError("Can't get mirror for adapter %s", element); + } + String nodeAdapter = null; + if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) { + nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString()); + } + + declareType(shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative()); + } + } + } + + private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element) { + if (!processedMatchRule.contains(element)) { + processedMatchRule.add(element); + TypeElement topDeclaringType = topDeclaringType(element); + MatchRuleDescriptor options = map.get(topDeclaringType); + if (options == null) { + options = new MatchRuleDescriptor(topDeclaringType); + map.put(topDeclaringType, options); + } + MatchRule[] matchRules = element.getAnnotationsByType(MatchRule.class); + for (MatchRule matchRule : matchRules) { + processMatchRule(element, options, matchRule); + } + } + } + + private void processMatchRule(Element element, MatchRuleDescriptor info, MatchRule matchRule) { + assert element instanceof TypeElement; + assert element.getKind() == ElementKind.CLASS; + TypeElement field = (TypeElement) element; + + TypeMirror fieldType = field.asType(); + if (fieldType.getKind() != TypeKind.DECLARED) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + MatchRule.class.getName(), element); + return; + } + + Element enclosing = element.getEnclosingElement(); + String declaringClass = ""; + String separator = ""; + Set<Element> originatingElementsList = info.originatingElements; + originatingElementsList.add(field); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { + String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + originatingElementsList.add(enclosing); + declaringClass = enclosing.getSimpleName() + separator + declaringClass; + separator = "."; + } else { + assert enclosing.getKind() == ElementKind.PACKAGE; + } + enclosing = enclosing.getEnclosingElement(); + } + + String rule = matchRule.value(); + try { + ArrayList<String> matches = new RuleParser(rule).generateVariants(); + for (String match : matches) { + info.options.add(new MatchRuleItem(match, declaringClass, field)); + } + } catch (RuleParseError e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), element); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.lang.annotation.*; + +import com.oracle.graal.nodes.*; + +/** + * This annotation declares a textual pattern for matching an HIR DAG. It's an s-expression with a + * node followed by its inputs. Node types are always uppercase and lowercase words are the names of + * nodes. + * + * <pre> + * NAME := [a-z][a-zA-Z0-9]* + * NODETYPE := [A-Z][a-zA-Z0-9]* + * NODEORNAME := NODE [ = NAME ] | NAME + * EXPRESSION := ( NODEORNAME [ EXPRESSION | NODEORNAME [ EXPRESSION | NODEORNAME ] ) + * </pre> + * + * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user. + * All matched nodes must be in the same block. + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Repeatable(value = MatchRules.class) +public @interface MatchRule { + String value(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.util.*; + +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.nodes.*; + +public class MatchRuleRegistry { + + private static final HashMap<Class<? extends NodeLIRBuilder>, Map<Class<? extends ValueNode>, List<MatchStatement>>> registry = new HashMap<>(); + + /** + * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass. + * + * @param theClass + * @return the set of {@link MatchStatement}s applicable to theClass. + */ + public synchronized static Map<Class<? extends ValueNode>, List<MatchStatement>> lookup(Class<? extends NodeLIRBuilder> theClass) { + Map<Class<? extends ValueNode>, List<MatchStatement>> result = registry.get(theClass); + + if (result == null) { + HashMap<Class<? extends NodeLIRBuilder>, List<MatchStatement>> localRules = new HashMap<>(); + ServiceLoader<MatchStatementSet> sl = ServiceLoader.loadInstalled(MatchStatementSet.class); + for (MatchStatementSet rules : sl) { + localRules.put(rules.forClass(), rules.statements()); + } + + // Walk the class hierarchy collecting lists and merge them together. The subclass + // rules are first which gives them preference over earlier rules. + Map<Class<? extends ValueNode>, List<MatchStatement>> rules = new HashMap<>(); + Class<?> currentClass = theClass; + do { + List<MatchStatement> statements = localRules.get(currentClass); + if (statements != null) { + for (MatchStatement statement : statements) { + Class<? extends ValueNode> nodeClass = statement.getPattern().nodeClass(); + List<MatchStatement> current = rules.get(nodeClass); + if (current == null) { + current = new ArrayList<>(); + rules.put(nodeClass, current); + } + current.add(statement); + } + } + currentClass = currentClass.getSuperclass(); + } while (currentClass != NodeLIRBuilder.class); + registry.put(theClass, rules); + assert registry.get(theClass) == rules; + result = rules; + } + + if (result.size() == 0) { + return null; + } + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.lang.annotation.*; + +/** + * The repeatable representation of {@link MatchRule}. Should never be used directly. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MatchRules { + MatchRule[] value(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.match.MatchPattern.Result; +import com.oracle.graal.nodes.*; + +/** + * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace + * one or more {@link ValueNode}s with a single {@link Value}. + */ + +public class MatchStatement { + private final String name; + private final MatchPattern pattern; + private final Class<? extends MatchGenerator> generatorClass; + + public MatchStatement(String name, MatchPattern pattern) { + this.name = name; + this.pattern = pattern; + this.generatorClass = null; + } + + public MatchStatement(String name, MatchPattern pattern, Class<? extends MatchGenerator> generator) { + this.name = name; + this.pattern = pattern; + this.generatorClass = generator; + } + + /** + * Attempt to match the current statement against a Node. + * + * @param builder the current builder instance. + * @param node the node to be matched + * @param nodes the nodes in the current block + * @return true if the statement matched something and set a {@link ComplexMatchResult} to be + * evaluated by the NodeLIRBuilder. + */ + public boolean generate(NodeLIRBuilder builder, ValueNode node, List<ScheduledNode> nodes) { + MatchContext context = new MatchContext(builder, this, node, nodes); + Result result = pattern.match(node, context); + if (result == Result.OK) { + result = context.validate(); + } + if (result == Result.OK) { + MatchGenerator generator = null; + try { + generator = generatorClass.newInstance(); + // Transfer values into gen + context.transferState(generator); + ComplexMatchResult value = generator.match(builder); + if (value != null) { + context.setResult(value); + return true; + } + } catch (InstantiationException | IllegalAccessException e) { + throw new GraalInternalError(e); + } + } else { + // This is fairly verbose for normal usage. + // if (result.code != MatchResultCode.WRONG_CLASS) { + // // Don't bother logging if it's just the wrong shape. + // Debug.log("while matching %s|%s %s %s %s", context.getRoot().toString(Verbosity.Id), + // context.getRoot().getClass().getSimpleName(), getName(), result, node.graph()); + // } + } + return false; + } + + public String formatMatch(ValueNode root) { + return pattern.formatMatch(root); + } + + public MatchPattern getPattern() { + return pattern; + } + + public String getName() { + return name; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.util.*; + +import com.oracle.graal.compiler.gen.*; + +public interface MatchStatementSet { + /** + * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement} + * instances. + */ + public Class<? extends NodeLIRBuilder> forClass(); + + /** + * @return the {@link MatchStatement}s available with this {@link NodeLIRBuilder} subclass. + */ + public List<MatchStatement> statements(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.lang.annotation.*; + +import com.oracle.graal.nodes.*; + +/** + * Describes the properties of a node for use when building a {@link MatchPattern}s. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Repeatable(value = MatchableNodes.class) +public @interface MatchableNode { + + /** + * The {@link ValueNode} subclass this annotation describes. These annotations might work better + * if they were directly on the node being described but that may complicate the annotation + * processing. + */ + Class<? extends ValueNode> value(); + + /** + * The name used in match patterns. Defaults to class.getSimpleName() with the word Node removed + * from the end. + */ + String shortName() default ""; + + /** + * The number of matchable inputs, which may be less than the real number of inputs. + */ + int inputs() default 0; + + /** + * A helper class to visit the inputs in a specified order. Should be a subclass of + * {@link MatchNodeAdapter}. + */ + Class<?> adapter() default MatchableNode.class; + + /** + * Can a pattern be matched with the operands swapped. This will cause swapped versions of + * patterns to be automatically generated. + */ + boolean commutative() default false; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.lang.annotation.*; + +/** + * A list of classes which contain one or more {@link MatchableNode} annotations describing nodes + * that may be used in match expressions. Those {@link MatchableNode} declarations are parsed before + * processing any {@link MatchRule}s. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MatchableNodeImport { + String[] value() default {}; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.match; + +import java.lang.annotation.*; + +/** + * The repeatable representation of {@link MatchableNode}. Should never be used directly. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MatchableNodes { + MatchableNode[] value() default {}; +}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Tue Apr 29 18:35:10 2014 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; @@ -57,9 +58,14 @@ appendPhase(new InliningPhase(canonicalizer)); appendPhase(new DeadCodeEliminationPhase()); - if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) { + boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue(); + if (reduceOrEliminate && OptCanonicalizer.getValue()) { appendPhase(canonicalizer); - appendPhase(new IterativeConditionalEliminationPhase(canonicalizer)); + if (FlowSensitiveReduction.getValue()) { + appendPhase(new IterativeFlowSensitiveReductionPhase(canonicalizer)); + } else { + appendPhase(new IterativeConditionalEliminationPhase(canonicalizer)); + } } } }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Tue Apr 29 18:35:10 2014 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.util.*; @@ -72,17 +73,17 @@ */ public abstract FrameMap newFrameMap(RegisterConfig registerConfig); - public abstract LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes); + public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes); public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub); - public abstract NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen); + public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen); /** * @param gen the LIRGenerator the BytecodeLIRBuilder should use * @param parser the bytecode parser the BytecodeLIRBuilder should use */ - public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) { + public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) { throw GraalInternalError.unimplemented("Baseline compilation is not available for this Backend!"); }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * 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.target; - -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.gen.*; -import com.oracle.graal.nodes.spi.*; - -/** - * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to - * {@link LIRGenerator} and {@link LIRInstruction}. - */ -public interface LIRGenLowerable { - - void generate(NodeLIRBuilder generator); -}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * 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.target; - -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.gen.*; -import com.oracle.graal.nodes.spi.*; - -/** - * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to - * {@link LIRGenerationResult} and {@link LIRInstruction}. - */ -public interface LIRGenResLowerable { - - void generate(NodeLIRBuilderTool generator, LIRGenerationResult genRes); -}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Apr 29 18:35:10 2014 +0200 @@ -184,7 +184,6 @@ class NodeUsageIterator implements Iterator<Node> { - private final int expectedModCount = usageModCount(); int index = -1; Node current; @@ -207,12 +206,10 @@ } public boolean hasNext() { - assert expectedModCount == usageModCount(); return current != null; } public Node next() { - assert expectedModCount == usageModCount(); Node result = current; if (result == null) { throw new NoSuchElementException();
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200 @@ -48,6 +48,7 @@ import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; /** * HotSpot AMD64 specific backend. @@ -71,7 +72,7 @@ } @Override - public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { return new AMD64HotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); } @@ -81,12 +82,12 @@ } @Override - public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) { + public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { return new AMD64HotSpotNodeLIRBuilder(graph, lirGen); } @Override - public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) { + public BytecodeLIRBuilder newBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) { return new AMD64HotSpotBytecodeLIRBuilder(gen, parser); }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBytecodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -33,7 +33,7 @@ public class AMD64HotSpotBytecodeLIRBuilder extends BytecodeLIRBuilder { - public AMD64HotSpotBytecodeLIRBuilder(LIRGenerator gen, BytecodeParserTool parser) { + public AMD64HotSpotBytecodeLIRBuilder(LIRGeneratorTool gen, BytecodeParserTool parser) { super(gen, parser); }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,17 +26,20 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import java.util.*; 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.compiler.amd64.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; +import com.oracle.graal.hotspot.data.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.type.*; import com.oracle.graal.hotspot.stubs.*; @@ -44,6 +47,7 @@ import com.oracle.graal.lir.StandardOp.NoOp; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; @@ -52,6 +56,7 @@ import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp; import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; +import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.gen.*; /** @@ -281,7 +286,8 @@ result = super.emitForeignCall(hotspotLinkage, deoptInfo, args); append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread)); } else { - result = super.emitForeignCall(hotspotLinkage, deoptInfo, args); + assert deoptInfo == null; + result = super.emitForeignCall(hotspotLinkage, null, args); } if (destroysRegisters) { @@ -542,6 +548,14 @@ return result; } + public static Register asNarrowReg(Value value) { + if (value.getPlatformKind() != NarrowOopStamp.NarrowOop) { + throw new InternalError("needed NarrowOop got: " + value.getKind()); + } else { + return asRegister(value); + } + } + public Value emitAtomicReadAndWrite(Value address, Value newValue) { PlatformKind kind = newValue.getPlatformKind(); Kind memKind = getMemoryKind(kind); @@ -551,4 +565,59 @@ return result; } + public static class CompareMemoryCompressedOp extends AMD64LIRInstruction { + @Alive({COMPOSITE}) protected AMD64AddressValue x; + @Use({CONST, REG}) protected Value y; + @State protected LIRFrameState state; + + public CompareMemoryCompressedOp(AMD64AddressValue x, Value y, LIRFrameState state) { + assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops; + this.x = x; + this.y = y; + this.state = state; + } + + @Override + protected void verify() { + assert y instanceof Constant || y.getPlatformKind() == NarrowOopStamp.NarrowOop; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + if (y instanceof Constant) { + Constant constant = (Constant) y; + if (constant.isNull()) { + masm.cmpl(x.toAddress(), 0); + } else { + if (y.getKind() == Kind.Object) { + crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true)); + } else if (y.getKind() == Kind.Long) { + crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true)); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + masm.cmpl(x.toAddress(), 0xdeaddead); + } + } else { + masm.cmpl(asNarrowReg(y), x.toAddress()); + } + } + } + + protected void emitCompareBranchMemoryCompressed(Value left, Value right, Condition cond, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability, LIRFrameState state) { + boolean mirrored = false; + if (left instanceof AMD64AddressValue) { + append(new CompareMemoryCompressedOp((AMD64AddressValue) left, right, state)); + } else { + assert right instanceof AMD64AddressValue; + append(new CompareMemoryCompressedOp((AMD64AddressValue) right, left, state)); + mirrored = true; + } + + Condition finalCondition = mirrored ? cond.mirror() : cond; + append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); + } }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.hotspot.amd64; - -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.compiler.amd64.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.calc.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.data.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.type.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; - -/** - * Specialized code gen for comparison with compressed memory. - */ - -public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole { - public static class CompareMemoryCompressedOp extends AMD64LIRInstruction { - @Alive({COMPOSITE}) protected AMD64AddressValue x; - @Use({CONST}) protected Value y; - @State protected LIRFrameState state; - - public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) { - assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops; - this.x = x; - this.y = y; - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - Constant constant = (Constant) y; - if (constant.isNull()) { - masm.cmpl(x.toAddress(), 0); - } else { - if (y.getKind() == Kind.Object) { - crb.recordInlineDataInCode(new OopData(0, HotSpotObjectConstant.asObject(constant), true)); - } else if (y.getKind() == Kind.Long) { - crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), HotSpotMetaspaceConstant.getMetaspaceObject(constant), true)); - } else { - throw GraalInternalError.shouldNotReachHere(); - } - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - masm.cmpl(x.toAddress(), 0xdeaddead); - } - } - } - - AMD64HotSpotMemoryPeephole(AMD64NodeLIRBuilder gen) { - super(gen); - } - - @Override - protected Kind getMemoryKind(Access access) { - PlatformKind kind = gen.getLIRGenerator().getPlatformKind(access.asNode().stamp()); - if (kind == NarrowOopStamp.NarrowOop) { - return Kind.Int; - } else { - return (Kind) kind; - } - } - - @Override - protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, - double trueLabelProbability) { - if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) { - ValueNode other = selectOtherInput(left, right, access); - Kind kind = getMemoryKind(access); - - if (other.isConstant() && kind == Kind.Object && access.isCompressible()) { - ensureEvaluated(other); - gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access))); - Condition finalCondition = right == access ? cond.mirror() : cond; - gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); - return true; - } - } - - return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability); - } -}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -32,7 +32,9 @@ import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.AMD64Address.Scale; import com.oracle.graal.compiler.amd64.*; +import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.match.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; @@ -45,16 +47,56 @@ import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; /** * LIR generator specialized for AMD64 HotSpot. */ +@MatchableNodeImport({"com.oracle.graal.hotspot.nodes.HotSpotMatchableNodes"}) public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder { - public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator gen) { + private static ValueNode filterCompression(ValueNode node) { + ValueNode result = node; + while (result instanceof CompressionNode) { + result = ((CompressionNode) result).getInput(); + } + return result; + } + + private void emitCompareCompressedMemory(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) { + Value value; + // This works by embedding the compressed form for constants, so force a constant instead of + // respecting what operand() would return. + if (valueNode.isConstant()) { + value = valueNode.asConstant(); + } else { + value = gen.load(operand(valueNode)); + } + AMD64AddressValue address = makeAddress(access); + + Condition cond = compare.condition(); + Value left; + Value right; + if (access == filterCompression(compare.x())) { + left = value; + right = address; + } else { + assert access == filterCompression(compare.y()); + left = address; + right = value; + cond = cond.mirror(); + } + + LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor()); + LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor()); + double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor()); + getGen().emitCompareBranchMemoryCompressed(left, right, cond, trueLabel, falseLabel, trueLabelProbability, getState(access)); + } + + public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) { super(graph, gen); - memoryPeephole = new AMD64HotSpotMemoryPeephole(this); assert gen instanceof AMD64HotSpotLIRGenerator; assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder; ((AMD64HotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack()); @@ -201,4 +243,40 @@ gen.emitMove(result, raxLocal); setResult(x, result); } + + /** + * Helper class to convert the NodeLIRBuilder into the current subclass. + */ + static abstract class AMD64HotSpotMatchGenerator implements MatchGenerator { + public AMD64HotSpotMatchGenerator() { + } + + public ComplexMatchResult match(NodeLIRBuilder gen) { + return match((AMD64HotSpotNodeLIRBuilder) gen); + } + + abstract public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen); + } + + @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))") + @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))") + @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))") + @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))") + public static class IfCompareMemory extends AMD64HotSpotMatchGenerator { + IfNode root; + Access access; + ValueNode value; + CompareNode compare; + + @Override + public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen) { + if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) { + return builder -> { + gen.emitCompareCompressedMemory(root, value, access, compare); + return null; + }; + } + return null; + } + } }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,12 +27,11 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; -public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRGenLowerable { +public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable { private final Constant functionPointer; @Input private final NodeInputList<ValueNode> args; @@ -44,7 +43,7 @@ } @Override - public void generate(NodeLIRBuilder generator) { + public void generate(NodeLIRBuilderTool generator) { AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator; Value[] parameter = new Value[args.count()]; JavaType[] parameterTypes = new JavaType[args.count()]; @@ -55,7 +54,7 @@ ResolvedJavaType returnType = stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess()); CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes, generator.getLIRGeneratorTool().target(), false); - ((AMD64LIRGenerator) gen.getLIRGeneratorTool()).emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args)); + gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args)); if (this.getKind() != Kind.Void) { generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn())); }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200 @@ -49,7 +49,6 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.gpu.*; @@ -70,6 +69,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; @@ -302,9 +302,8 @@ for (CodeAnnotation annotation : hostCode.getAnnotations()) { result.addAnnotation(annotation); } - CompilationResult.Mark[] noMarks = {}; for (Mark mark : hostCode.getMarks()) { - result.recordMark(mark.pcOffset, mark.id, noMarks); + result.recordMark(mark.pcOffset, mark.id); } for (ExceptionHandler handler : hostCode.getExceptionHandlers()) { result.recordExceptionHandler(handler.pcOffset, handler.handlerPos); @@ -376,7 +375,7 @@ } @Override - public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { return new HSAILHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); } @@ -386,7 +385,7 @@ } @Override - public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) { + public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { return new HSAILHotSpotNodeLIRBuilder(graph, lirGen); }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Tue Apr 29 18:35:10 2014 +0200 @@ -151,6 +151,7 @@ return nodeResult; } + @Override public Value emitAtomicReadAndAdd(Value address, Value delta) { PlatformKind kind = delta.getPlatformKind(); Kind memKind = getMemoryKind(kind); @@ -161,6 +162,16 @@ } @Override + public Value emitAtomicReadAndWrite(Value address, Value newValue) { + PlatformKind kind = newValue.getPlatformKind(); + Kind memKind = getMemoryKind(kind); + Variable result = newVariable(kind); + HSAILAddressValue addressValue = asAddressValue(address); + append(new HSAILMove.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue))); + return result; + } + + @Override public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) { emitDeoptimizeInner(actionAndReason, state, "emitDeoptimize"); }
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -44,7 +44,7 @@ */ public class HSAILHotSpotNodeLIRBuilder extends HSAILNodeLIRBuilder implements HotSpotNodeLIRBuilder { - public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) { + public HSAILHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { super(graph, lirGen); }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200 @@ -38,7 +38,6 @@ import com.oracle.graal.asm.ptx.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.compiler.gen.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.gpu.*; @@ -55,6 +54,7 @@ import com.oracle.graal.lir.ptx.PTXControlFlow.PTXPredicatedLIRInstruction; import com.oracle.graal.lir.ptx.PTXMemOp.LoadReturnAddrOp; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; @@ -356,12 +356,12 @@ } @Override - public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { return new PTXHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); } @Override - public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) { + public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { return new PTXHotSpotNodeLIRBuilder(graph, lirGen); }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -35,7 +35,7 @@ */ public class PTXHotSpotNodeLIRBuilder extends PTXNodeLIRBuilder implements HotSpotNodeLIRBuilder { - protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) { + protected PTXHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { super(graph, lirGen); }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizationStub.java Tue Apr 29 18:35:10 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,11 +35,14 @@ public SPARCDeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(providers, target, linkage); - registerConfig = new SPARCHotSpotRegisterConfig(target, new Register[]{o0, o1, o2, o3, o4, o5, o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, f0, f1, f2, f3, f4, f5, f6, f7}); + // This is basically the maximum we can spare. All other G and O register are used. + Register[] allocatable = new Register[]{g1, g3, g4, g5, o0, o1, o2, o3, o4}; + registerConfig = new SPARCHotSpotRegisterConfig(target, allocatable); } @Override public RegisterConfig getRegisterConfig() { return registerConfig; } + }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Tue Apr 29 18:35:10 2014 +0200 @@ -44,7 +44,6 @@ import com.oracle.graal.asm.sparc.SPARCMacroAssembler.RestoreWindow; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.gen.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.hotspot.meta.*; @@ -55,6 +54,7 @@ import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.sparc.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; /** * HotSpot SPARC specific backend. @@ -78,12 +78,17 @@ } @Override - public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); } @Override - public NodeLIRBuilder newNodeLIRGenerator(StructuredGraph graph, LIRGenerator lirGen) { + public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { + return new SPARCHotSpotLIRGenerationResult(lir, frameMap, stub); + } + + @Override + public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { return new SPARCHotSpotNodeLIRBuilder(graph, lirGen); } @@ -190,11 +195,6 @@ } @Override - public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { - return new LIRGenerationResultBase(lir, frameMap); - } - - @Override public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; FrameMap frameMap = crb.frameMap;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,9 +48,8 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // Save last Java frame. - new Add(stackPointer, new SPARCAddress(stackPointer, 0).getDisplacement(), g4).emit(masm); + new Add(stackPointer, STACK_BIAS, g4).emit(masm); new Stx(g4, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm); // Save the thread register when calling out to the runtime.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.sparc; + +import static com.oracle.graal.sparc.SPARC.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.sparc.*; +import com.oracle.graal.lir.asm.*; + +/** + * Emits code that enters a stack frame which is tailored to call the C++ method + * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME") +final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction { + + private final Register thread; + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + @Alive(REG) AllocatableValue framePc; + @Alive(REG) AllocatableValue senderSp; + @Temp(REG) AllocatableValue scratch; + + SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch) { + this.thread = thread; + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.framePc = framePc; + this.senderSp = senderSp; + this.scratch = scratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + final int totalFrameSize = crb.frameMap.totalFrameSize(); + Register framePcRegister = asRegister(framePc); + Register senderSpRegister = asRegister(senderSp); + Register scratchRegister = asRegister(scratch); + + // Save final sender SP to O5_savedSP. + new Mov(senderSpRegister, o5).emit(masm); + + // Load final frame PC. + new Mov(framePcRegister, o7).emit(masm); + + // Allocate a full sized frame. + new Save(sp, -totalFrameSize, sp).emit(masm); + + new Mov(i0, o0).emit(masm); + new Mov(i1, o1).emit(masm); + new Mov(i2, o2).emit(masm); + new Mov(i3, o3).emit(masm); + new Mov(i4, o4).emit(masm); + + // Set up last Java values. + new Add(sp, STACK_BIAS, scratchRegister).emit(masm); + new Stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm); + + // Clear last Java PC. + new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm); + + /* + * Safe thread register manually since we are not using LEAF_SP for {@link + * DeoptimizationStub#UNPACK_FRAMES}. + */ + new Mov(thread, l7).emit(masm); + } +}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Tue Apr 29 18:35:10 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,14 +22,49 @@ */ package com.oracle.graal.hotspot.sparc; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.lir.gen.*; -public interface SPARCHotSpotLIRGenerationResult extends LIRGenerationResult { +public class SPARCHotSpotLIRGenerationResult extends LIRGenerationResultBase { + + /** + * The slot reserved for storing the original return address when a frame is marked for + * deoptimization. The return address slot in the callee is overwritten with the address of a + * deoptimization stub. + */ + private StackSlot deoptimizationRescueSlot; + private final Object stub; + + /** + * Map from debug infos that need to be updated with callee save information to the operations + * that provide the information. + */ + private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = new HashMap<>(); - StackSlot getDeoptimizationRescueSlot(); + public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { + super(lir, frameMap); + this.stub = stub; + } + + StackSlot getDeoptimizationRescueSlot() { + return deoptimizationRescueSlot; + } - Stub getStub(); + public final void setDeoptimizationRescueSlot(StackSlot deoptimizationRescueSlot) { + this.deoptimizationRescueSlot = deoptimizationRescueSlot; + } + + Stub getStub() { + return (Stub) stub; + } + + Map<LIRFrameState, SaveRegistersOp> getCalleeSaveInfo() { + return calleeSaveInfo; + } }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Tue Apr 29 18:35:10 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.nodes.UncommonTrapCallNode.*; +import static com.oracle.graal.sparc.SPARC.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -264,38 +266,78 @@ throw GraalInternalError.unimplemented(); } + /** + * @param savedRegisters the registers saved by this operation which may be subject to pruning + * @param savedRegisterLocations the slots to which the registers are saved + * @param supportsRemove determines if registers can be pruned + */ + protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations, boolean supportsRemove) { + SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove); + append(save); + return save; + } + public SaveRegistersOp emitSaveAllRegisters() { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + // We save all registers that were not saved by the save instruction. + // @formatter:off + Register[] savedRegisters = { + // CPU + g1, g3, g4, g5, + // FPU + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31 + }; + // @formatter:on + StackSlot[] savedRegisterLocations = new StackSlot[savedRegisters.length]; + for (int i = 0; i < savedRegisters.length; i++) { + PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory()); + assert kind != Kind.Illegal; + StackSlot spillSlot = getResult().getFrameMap().allocateSpillSlot(kind); + savedRegisterLocations[i] = spillSlot; + } + return emitSaveRegisters(savedRegisters, savedRegisterLocations, false); } public void emitLeaveCurrentStackFrame() { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + append(new SPARCHotSpotLeaveCurrentStackFrameOp()); } public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp()); } public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + Register thread = getProviders().getRegisters().getThreadRegister(); + Variable framePcVariable = load(framePc); + Variable senderSpVariable = load(senderSp); + Variable scratchVariable = newVariable(getHostWordKind()); + append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable)); } public void emitLeaveUnpackFramesStackFrame() { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + Register thread = getProviders().getRegisters().getThreadRegister(); + append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset())); } public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + Variable frameSizeVariable = load(frameSize); + Variable framePcVariable = load(framePc); + Variable senderSpVariable = load(senderSp); + Variable initialInfoVariable = load(initialInfo); + append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable)); } public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented(); + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP); + + Register threadRegister = getProviders().getRegisters().getThreadRegister(); + Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister(); + append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister)); + Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(Kind.Long), trapRequest); + append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister)); + + return result; } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.sparc; + +import static com.oracle.graal.sparc.SPARC.*; + +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +/** + * Pops the current frame off the stack. + */ +@Opcode("LEAVE_CURRENT_STACK_FRAME") +final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCHotSpotEpilogueOp { + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // Save O registers over restore. + new Mov(o0, i0).emit(masm); + new Mov(o1, i1).emit(masm); + new Mov(o2, i2).emit(masm); + new Mov(o3, i3).emit(masm); + new Mov(o4, i4).emit(masm); + + leaveFrame(crb); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.sparc; + +import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import static com.oracle.graal.sparc.SPARC.*; + +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +/** + * Pops the current frame off the stack including the return address. + */ +@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME") +final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCHotSpotEpilogueOp { + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + // Save O registers over restore. + new Mov(o0, i0).emit(masm); + new Mov(o1, i1).emit(masm); + new Mov(o2, i2).emit(masm); + new Mov(o3, i3).emit(masm); + new Mov(o4, i4).emit(masm); + + new RestoreWindow().emit(masm); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.sparc; + +import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import static com.oracle.graal.sparc.SPARC.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.sparc.*; +import com.oracle.graal.lir.asm.*; + +/** + * Emits code that leaves a stack frame which is tailored to call the C++ method + * {@link DeoptimizationStub#UNPACK_FRAMES Deoptimization::unpack_frames}. + */ +@Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME") +final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction { + + private final Register thread; + private final int threadLastJavaSpOffset; + private final int threadLastJavaPcOffset; + private final int threadJavaFrameAnchorFlagsOffset; + + SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) { + this.thread = thread; + this.threadLastJavaSpOffset = threadLastJavaSpOffset; + this.threadLastJavaPcOffset = threadLastJavaPcOffset; + this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + /* + * Safe thread register manually since we are not using LEAF_SP for {@link + * DeoptimizationStub#UNPACK_FRAMES}. + */ + new Mov(l7, thread).emit(masm); + + // Clear last Java frame values. + new Stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)).emit(masm); + new Stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)).emit(masm); + new Stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)).emit(masm); + } +}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -43,7 +43,7 @@ public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder { - public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGenerator lirGen) { + public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { super(graph, lirGen); assert gen instanceof SPARCHotSpotLIRGenerator; assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.sparc; + +import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import static com.oracle.graal.sparc.SPARC.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.sparc.*; +import com.oracle.graal.lir.asm.*; + +/** + * Pushes an interpreter frame to the stack. + */ +@Opcode("PUSH_INTERPRETER_FRAME") +final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction { + + @Alive(REG) AllocatableValue frameSize; + @Alive(REG) AllocatableValue framePc; + @Alive(REG) AllocatableValue senderSp; + @Alive(REG) AllocatableValue initialInfo; + + SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) { + this.frameSize = frameSize; + this.framePc = framePc; + this.senderSp = senderSp; + this.initialInfo = initialInfo; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + final Register frameSizeRegister = asRegister(frameSize); + final Register framePcRegister = asRegister(framePc); + final Register senderSpRegister = asRegister(senderSp); + + // Save sender SP to O5_savedSP. + new Mov(senderSpRegister, o5).emit(masm); + + new Neg(frameSizeRegister).emit(masm); + new Save(sp, frameSizeRegister, sp).emit(masm); + + new Mov(i0, o0).emit(masm); + new Mov(i1, o1).emit(masm); + new Mov(i2, o2).emit(masm); + new Mov(i3, o3).emit(masm); + new Mov(i4, o4).emit(masm); + + // NOTE: Don't touch I5 as it contains valuable saved SP! + + // Move frame's new PC into i7 + new Mov(framePcRegister, i7).emit(masm); + } +}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Apr 29 18:35:10 2014 +0200 @@ -98,25 +98,27 @@ private static Register[] initAllocatable(boolean reserveForHeapBase) { Register[] registers = null; - // @formatter:off if (reserveForHeapBase) { - registers = new Register[] { + // @formatter:off + registers = new Register[]{ // TODO this is not complete o0, o1, o2, o3, o4, o5, /*o6,*/ o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ f0, f1, f2, f3, f4, f5, f6, f7 - }; + }; + // @formatter:on } else { - registers = new Register[] { + // @formatter:off + registers = new Register[]{ // TODO this is not complete o0, o1, o2, o3, o4, o5, /*o6,*/ o7, l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ f0, f1, f2, f3, f4, f5, f6, f7 - }; + }; + // @formatter:on } - // @formatter:on if (RegisterPressure.getValue() != null) { String[] names = RegisterPressure.getValue().split(",");
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -36,6 +36,8 @@ import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.sparc.*; +import edu.umd.cs.findbugs.annotations.*; + /** * Emits a safepoint poll. */ @@ -43,7 +45,7 @@ public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction { @State protected LIRFrameState state; - @Temp({OperandFlag.REG}) private AllocatableValue temp; + @SuppressFBWarnings(value = "BC_IMPOSSIBLE_CAST", justification = "changed by the register allocator") @Temp({OperandFlag.REG}) private AllocatableValue temp; private final HotSpotVMConfig config;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Tue Apr 29 18:35:10 2014 +0200 @@ -63,7 +63,7 @@ try (Scope s = Debug.scope("RegisterReplacements", new DebugDumpScope("RegisterReplacements"))) { ServiceLoader<ReplacementsProvider> sl = ServiceLoader.loadInstalled(ReplacementsProvider.class); for (ReplacementsProvider replacementsProvider : sl) { - replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, replacements, providers.getCodeCache().getTarget()); + replacementsProvider.registerReplacements(providers.getMetaAccess(), lowerer, providers.getSnippetReflection(), replacements, providers.getCodeCache().getTarget()); } if (BootstrapReplacements.getValue()) { for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue Apr 29 18:35:10 2014 +0200 @@ -794,6 +794,7 @@ // offsets, ... @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages; @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging; + @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias; @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset; @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Tue Apr 29 18:35:10 2014 +0200 @@ -99,7 +99,6 @@ private static final boolean DUMP_STATIC = false; - public static String excludedClassPrefix = null; public static boolean enabled = false; public static final ConcurrentHashMap<String, Integer> indexes = new ConcurrentHashMap<>(); @@ -108,14 +107,23 @@ public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>(); @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block") - public static int getIndex(DynamicCounterNode counter) { + private static int getIndex(DynamicCounterNode counter) { if (!enabled) { throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName()); } - String name = counter.getName(); + String name; String group = counter.getGroup(); - name = counter.isWithContext() && counter.graph().method() != null ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name + - "#" + group; + if (counter.isWithContext()) { + StructuredGraph graph = counter.graph(); + name = counter.getName() + " @ " + graph.graphId() + ":" + (graph.method() == null ? "" : MetaUtil.format("%h.%n", graph.method())); + if (graph.name != null) { + name += " (" + graph.name + ")"; + } + name += "#" + group; + + } else { + name = counter.getName() + "#" + group; + } Integer index = indexes.get(name); if (index == null) { synchronized (BenchmarkCounters.class) { @@ -135,7 +143,7 @@ return index; } - public static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) { + private static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) { if (!groups.isEmpty()) { out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======"); for (String group : new TreeSet<>(groups)) { @@ -152,7 +160,7 @@ } } - public static synchronized void clear(long[] counters) { + private static synchronized void clear(long[] counters) { delta = counters; } @@ -228,7 +236,7 @@ return (counter * 200 + 1) / sum / 2; } - public abstract static class CallbackOutputStream extends OutputStream { + private abstract static class CallbackOutputStream extends OutputStream { protected final PrintStream delegate; private final byte[][] patterns; @@ -281,25 +289,30 @@ final class BenchmarkCountersOutputStream extends CallbackOutputStream { private long startTime; + private boolean running; private boolean waitingForEnd; private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) { - super(delegate, new String[]{start, end, "\n"}); + super(delegate, new String[]{"\n", end, start}); } @Override protected void patternFound(int index) { switch (index) { - case 0: + case 2: startTime = System.nanoTime(); BenchmarkCounters.clear(compilerToVM.collectCounters()); + running = true; break; case 1: - waitingForEnd = true; + if (running) { + waitingForEnd = true; + } break; - case 2: + case 0: if (waitingForEnd) { waitingForEnd = false; + running = false; BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters(), 100); } break; @@ -321,7 +334,6 @@ throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out"); } } - excludedClassPrefix = "Lcom/oracle/graal/"; enabled = true; } if (Options.GenericDynamicCounters.getValue()) { @@ -363,26 +375,24 @@ public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) { StructuredGraph graph = counter.graph(); - if (excludedClassPrefix == null || (counter.graph().method() != null && !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix))) { - ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false)); + ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false)); - int index = BenchmarkCounters.getIndex(counter); - if (index >= config.graalCountersSize) { - throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")"); - } - ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset, graph); - ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false)); - ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph); - ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); - IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement())); - WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false)); + int index = BenchmarkCounters.getIndex(counter); + if (index >= config.graalCountersSize) { + throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")"); + } + ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, wordKind, config.graalCountersThreadOffset, graph); + ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false)); + ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph); + ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); + IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement())); + WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false)); - graph.addBeforeFixed(counter, thread); - graph.addBeforeFixed(counter, readArray); - graph.addBeforeFixed(counter, read); - graph.addBeforeFixed(counter, write); - } + graph.addBeforeFixed(counter, thread); + graph.addBeforeFixed(counter, readArray); + graph.addBeforeFixed(counter, read); + graph.addBeforeFixed(counter, write); graph.removeFixed(counter); } }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Apr 29 18:35:10 2014 +0200 @@ -192,8 +192,10 @@ if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { newObjectSnippets.lower((NewMultiArrayNode) n, tool); } - } else if (n instanceof LoadExceptionObjectNode) { - exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool); + } else if (n instanceof ExceptionObjectNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + lowerExceptionObjectNode((ExceptionObjectNode) n, tool); + } } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) { // Nothing to do for division nodes. The HotSpot signal handler catches divisions by // zero and the MIN_VALUE / -1 cases. @@ -732,6 +734,19 @@ } } + private void lowerExceptionObjectNode(ExceptionObjectNode n, LoweringTool tool) { + LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) n.predecessor()).getLocationIdentity(); + BeginNode entry = n.graph().add(new KillingBeginNode(locationsKilledByInvoke)); + LoadExceptionObjectNode loadException = n.graph().add(new LoadExceptionObjectNode(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Throwable.class)))); + + loadException.setStateAfter(n.stateAfter()); + n.replaceAtUsages(InputType.Value, loadException); + n.graph().replaceFixedWithFixed(n, entry); + entry.graph().addAfterFixed(entry, loadException); + + exceptionObjectSnippets.lower(loadException, registers, tool); + } + public static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) { StructuredGraph graph = commit.graph(); for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Tue Apr 29 18:35:10 2014 +0200 @@ -286,4 +286,8 @@ public String disassemble(ResolvedJavaMethod method) { return new BytecodeDisassembler().disassemble(method); } + + public SpeculationLog createSpeculationLog() { + return new HotSpotSpeculationLog(); + } }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Apr 29 18:35:10 2014 +0200 @@ -119,7 +119,14 @@ registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION); registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); + + /* + * We cannot use LEAF_SP here because on some architectures we have to align the stack + * manually before calling into the VM. See {@link + * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}. + */ registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION); + registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS); link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,9 +27,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -37,7 +35,7 @@ * Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for * the entire execution of the associated method. */ -public final class AllocaNode extends FixedWithNextNode implements LIRGenResLowerable { +public final class AllocaNode extends FixedWithNextNode implements LIRLowerable { /** * The number of slots in block. @@ -58,8 +56,8 @@ } @Override - public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) { - StackSlot array = res.getFrameMap().allocateStackSlots(slots, objects, null); + public void generate(NodeLIRBuilderTool gen) { + StackSlot array = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(slots, objects, null); Value result = gen.getLIRGeneratorTool().emitAddress(array); gen.setResult(this, result); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,12 +24,11 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; /** @@ -39,7 +38,7 @@ * check on the object. */ @NodeInfo(allowedUsageTypes = {InputType.Memory}) -public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorEnter, MemoryCheckpoint.Single { +public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single { private int lockDepth; @@ -59,7 +58,7 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { assert lockDepth != -1; HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); StackSlot slot = hsGen.getLockSlot(lockDepth);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,8 +23,6 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; @@ -32,7 +30,7 @@ /** * Converts a compile-time constant Java string into a C string installed with the generated code. */ -public final class CStringNode extends FloatingNode implements LIRGenLowerable { +public final class CStringNode extends FloatingNode implements LIRLowerable { private final String string; @@ -41,7 +39,7 @@ this.string = string; } - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { gen.setResult(this, emitCString(gen, string)); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -93,6 +93,10 @@ throw GraalInternalError.shouldNotReachHere(); } + public ValueNode getInput() { + return input; + } + @Override public Node canonical(CanonicalizerTool tool) { if (input instanceof CompressionNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -38,7 +37,7 @@ * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray * instruction. */ -public final class DimensionsNode extends FixedWithNextNode implements LIRGenResLowerable { +public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable { private final int rank; @@ -48,12 +47,13 @@ } @Override - public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) { + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool lirGen = gen.getLIRGeneratorTool(); int size = rank * 4; - int wordSize = gen.getLIRGeneratorTool().target().wordSize; + int wordSize = lirGen.target().wordSize; int slots = roundUp(size, wordSize) / wordSize; - StackSlot array = res.getFrameMap().allocateStackSlots(slots, new BitSet(0), null); - Value result = gen.getLIRGeneratorTool().emitAddress(array); + StackSlot array = lirGen.getResult().getFrameMap().allocateStackSlots(slots, new BitSet(0), null); + Value result = lirGen.emitAddress(array); gen.setResult(this, result); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,13 +23,12 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; 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.word.*; /** @@ -39,7 +38,7 @@ * expected value or the compared against value instead of a boolean. */ @NodeInfo(allowedUsageTypes = {InputType.Memory}) -public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint.Single { +public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { @Input private ValueNode object; @Input private ValueNode offset; @@ -79,7 +78,7 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { ((HotSpotNodeLIRBuilder) gen).visitDirectCompareAndSwap(this); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.compiler.match.*; +import com.oracle.graal.nodes.*; + +@MatchableNode(shortName = "Compression", value = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class) +public class HotSpotMatchableNodes { + public static class CompressionNodeAdapter extends MatchNodeAdapter { + @Override + protected ValueNode getFirstInput(ValueNode node) { + return ((CompressionNode) node).getInput(); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadExceptionObjectNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009, 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.hotspot.nodes; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable { + + public LoadExceptionObjectNode(Stamp stamp) { + super(stamp); + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } +}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,8 +26,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; @@ -35,16 +33,16 @@ /** * Node that is used to maintain a stack based counter of how many locks are currently held. */ -public final class MonitorCounterNode extends FloatingNode implements LIRGenResLowerable { +public final class MonitorCounterNode extends FloatingNode implements LIRLowerable { private MonitorCounterNode() { super(null); } @Override - public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) { + public void generate(NodeLIRBuilderTool gen) { assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance"; - StackSlot counter = res.getFrameMap().allocateStackSlots(1, new BitSet(0), null); + StackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMap().allocateStackSlots(1, new BitSet(0), null); Value result = gen.getLIRGeneratorTool().emitAddress(counter); gen.setResult(this, result); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue Apr 29 18:35:10 2014 +0200 @@ -25,18 +25,17 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; /** * A call to the {@link NewArrayStub}. */ -public class NewArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable { +public class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -61,9 +60,9 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY); - Variable result = gen.getLIRGenerator().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length)); + Variable result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(hub), gen.operand(length)); gen.setResult(this, result); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,13 +24,12 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; -public class PrefetchAllocateNode extends FixedWithNextNode implements LIRGenLowerable { +public class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable { @Input private ValueNode distance; @Input private ValueNode address; @@ -42,7 +41,7 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { ((HotSpotNodeLIRBuilder) gen).emitPrefetchAllocate(address, distance); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.java.*; @@ -41,7 +40,7 @@ * Performs a tail call to the specified target compiled method, with the parameter taken from the * supplied FrameState. */ -public class TailcallNode extends FixedWithNextNode implements LIRGenResLowerable { +public class TailcallNode extends FixedWithNextNode implements LIRLowerable { @Input(InputType.State) private FrameState frameState; @Input private ValueNode target; @@ -58,20 +57,21 @@ this.frameState = frameState; } - public void generate(NodeLIRBuilderTool gen, LIRGenerationResult res) { + public void generate(NodeLIRBuilderTool gen) { HotSpotVMConfig config = runtime().getConfig(); + LIRGeneratorTool lirGen = gen.getLIRGeneratorTool(); ResolvedJavaMethod method = frameState.method(); boolean isStatic = method.isStatic(); JavaType[] signature = MetaUtil.signatureToTypes(method.getSignature(), isStatic ? null : method.getDeclaringClass()); - CallingConvention cc = res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.getLIRGeneratorTool().target(), false); + CallingConvention cc = lirGen.getResult().getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, lirGen.target(), false); List<ValueNode> parameters = new ArrayList<>(); for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += HIRFrameStateBuilder.stackSlots(frameState.localAt(slot).getKind())) { parameters.add(frameState.localAt(slot)); } Value[] args = gen.visitInvokeArguments(cc, parameters); - Value address = gen.getLIRGeneratorTool().emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0); - Value entry = gen.getLIRGeneratorTool().emitLoad(Kind.Long, address, null); + Value address = lirGen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0); + Value entry = lirGen.emitLoad(Kind.Long, address, null); HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen; hsgen.emitTailcall(args, entry); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java Tue Apr 29 18:35:10 2014 +0200 @@ -34,7 +34,7 @@ public class CallSiteSubstitutions implements ReplacementsProvider { @Override - public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) { + public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { replacements.registerSubstitutions(ConstantCallSiteSubstitutions.class); replacements.registerSubstitutions(MutableCallSiteSubstitutions.class); replacements.registerSubstitutions(VolatileCallSiteSubstitutions.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; @@ -32,7 +33,7 @@ public class HotSpotSubstitutions implements ReplacementsProvider { @Override - public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) { + public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { replacements.registerSubstitutions(ObjectSubstitutions.class); replacements.registerSubstitutions(SystemSubstitutions.class); replacements.registerSubstitutions(ThreadSubstitutions.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Tue Apr 29 18:35:10 2014 +0200 @@ -30,9 +30,9 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.common.type.*; 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.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; @@ -44,6 +44,12 @@ /** * Snippet for loading the exception object at the start of an exception dispatcher. + * <p> + * The frame state upon entry to an exception handler is such that it is a + * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the + * exception object (per the JVM spec) to rethrow. This means that the code generated for this node + * must not cause a deoptimization as the runtime/interpreter would not have a valid location to + * find the exception object to be rethrown. */ public class LoadExceptionObjectSnippets implements Snippets {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java Tue Apr 29 18:35:10 2014 +0200 @@ -126,8 +126,8 @@ // Pop all the frames we must move/replace. // // Frame picture (youngest to oldest) - // 1: self-frame (no frame link) - // 2: deoptimizing frame (no frame link) + // 1: self-frame + // 2: deoptimizing frame // 3: caller of deoptimizing frame (could be compiled/interpreted). // Pop self-frame. @@ -136,7 +136,7 @@ // Load the initial info we should save (e.g. frame pointer). final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset()); - // Pop deoptimized frame + // Pop deoptimized frame. final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset()); LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo); @@ -144,13 +144,15 @@ * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for * total size of the interpreter frames plus shadow page size. Bang one page at a time * because large sizes can bang beyond yellow and red zones. + * + * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository. */ final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset()); final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages(); Word stackPointer = readRegister(stackPointerRegister); for (int i = 1; i < bangPages; i++) { - stackPointer.writeInt(-(i * pageSize()), i); + stackPointer.writeInt((-i * pageSize()) + stackBias(), 0); } // Load number of interpreter frames. @@ -221,6 +223,19 @@ return config().useStackBanging ? config().stackShadowPages : 0; } + /** + * Returns the stack bias for the host architecture. + * + * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository. + * + * @return stack bias + */ + @Deprecated + @Fold + private static int stackBias() { + return config().stackBias; + } + @Fold private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() { return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.hotspot.stubs; -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.stubs.StubUtil.*; @@ -61,15 +60,9 @@ protected Arguments makeArguments(SnippetInfo stub) { HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) providers.getMetaAccess().lookupJavaType(int[].class); - // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we - // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since - // the int[] class will never be unloaded. - Constant intArrayHub = intArrayType.klass(); - intArrayHub = Constant.forIntegerKind(runtime().getTarget().wordKind, intArrayHub.asLong()); - Arguments args = new Arguments(stub, GuardsStage.FLOATING_GUARDS, LoweringTool.StandardLoweringStage.HIGH_TIER); args.add("hub", null); - args.addConst("intArrayHub", intArrayHub); + args.addConst("intArrayHub", intArrayType.klass()); args.addConst("threadRegister", providers.getRegisters().getThreadRegister()); return args; }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -326,6 +326,7 @@ } finally { lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); + assert lockedObjects.length == monitorIds.length; } }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,8 +23,9 @@ package com.oracle.graal.jtt.except; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -61,12 +62,12 @@ } } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.except; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -49,17 +50,17 @@ } } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 3); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.except; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -56,17 +57,17 @@ } } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.except; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Throw_InNested extends JTTTest { @@ -48,12 +49,12 @@ return i; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.except; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Throw_Synchronized01 extends JTTTest { @@ -38,12 +39,12 @@ throw new Exception(); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.except; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Throw_Synchronized02 extends JTTTest { @@ -36,12 +37,12 @@ throw new Exception(); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.except; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Throw_Synchronized03 extends JTTTest { @@ -41,12 +42,12 @@ throw new Exception(); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.hotpath; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -37,27 +38,27 @@ return sum; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 80); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,8 +23,9 @@ // Checkstyle: stop package com.oracle.graal.jtt.hotpath; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -55,12 +56,12 @@ return (int) (b + c + s + i + l + f + d); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 40); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1000); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ package com.oracle.graal.jtt.hotpath; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -104,12 +105,12 @@ } } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 40); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 80); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java Tue Apr 29 18:35:10 2014 +0200 @@ -25,8 +25,9 @@ import java.util.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -106,7 +107,7 @@ } } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 5); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,8 +23,9 @@ // Checkstyle: stop package com.oracle.graal.jtt.hotpath; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -48,7 +49,7 @@ return sum; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 15); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.hotspot; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /** * @bug 6196102 @@ -46,7 +47,7 @@ return "ok"; } - @LongTest + @Test public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.hotspot; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; //@formatter:off @@ -50,7 +51,7 @@ return 95; } - @LongTest + @Test public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.util.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -45,17 +46,17 @@ C } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.io.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -58,7 +59,7 @@ out.println(test(10000)); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 10000); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,10 +24,11 @@ import java.lang.reflect.*; +import org.junit.*; + import sun.misc.*; import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -55,7 +56,7 @@ } } - @LongTest + @Test public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.net.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -43,22 +44,22 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 5); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Class_Literal01 extends JTTTest { @@ -45,27 +46,27 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Class_asSubclass01 extends JTTTest { @@ -53,27 +54,27 @@ return i; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Class_cast01 extends JTTTest { @@ -57,27 +58,27 @@ return i; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Class_forName01 extends JTTTest { @@ -45,27 +46,27 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Class_forName02 extends JTTTest { @@ -51,27 +52,27 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.net.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -56,32 +57,32 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -48,32 +49,32 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.net.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -41,17 +42,17 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 5); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -81,27 +82,27 @@ } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Object_getClass01 extends JTTTest { @@ -49,27 +50,27 @@ return null; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Object_toString01 extends JTTTest { @@ -47,17 +48,17 @@ return string; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -33,17 +34,17 @@ return ("id" + i).intern() == ("id" + i).intern(); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -33,17 +34,17 @@ return ("id" + i).intern().equals("id" + i); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.loop; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class LoopParseLong extends JTTTest { @@ -98,7 +99,7 @@ return negative ? result : -result; } - @LongTest + @Test public void run0() throws Throwable { runTest("testShortened", "7", 10); runTest("testShortened", "-100", 10);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.loop; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -58,7 +59,7 @@ return "" + ('a' + count); } - @LongTest + @Test public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.micro; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -33,7 +34,7 @@ return p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.micro; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -155,32 +156,32 @@ ((Matrix[]) array)[val % array.length] = new Matrix(number); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.micro; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -57,7 +58,7 @@ return Integer.valueOf(foo(new String[]{"asdf"})); } - @LongTest + @Test public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.micro; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -58,7 +59,7 @@ Object c = b; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.util.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -117,22 +118,22 @@ return c2 ? 1 : 0; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 10); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 20); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 40); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.io.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -44,7 +45,7 @@ return (String) arg; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", (Object) null); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.optimize; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* * Tests value numbering of instanceof operations. @@ -76,17 +77,17 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -37,22 +38,22 @@ return Class_getField01.class.getField(input).getName(); } - @LongTest + @Test public void run0() throws Throwable { runTest("test", "test"); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", "field"); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", "field2"); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", "field3"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -42,27 +43,27 @@ public String field4; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", "test"); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", "field"); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", "field2"); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", "field3"); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", "field4"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -39,17 +40,17 @@ field = args[0]; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", "test"); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", "main"); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", "xx"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -52,37 +53,37 @@ field = args[0]; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Class_newInstance03 extends JTTTest { @@ -45,27 +46,27 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -59,47 +60,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -61,47 +62,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.lang.reflect.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -87,47 +88,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -61,47 +62,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -59,47 +60,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -67,47 +68,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -69,47 +70,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -69,47 +70,47 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); } - @LongTest + @Test public void run5() throws Throwable { runTest("test", 5); } - @LongTest + @Test public void run6() throws Throwable { runTest("test", 6); } - @LongTest + @Test public void run7() throws Throwable { runTest("test", 7); } - @LongTest + @Test public void run8() throws Throwable { runTest("test", 8); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.lang.reflect.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -56,27 +57,27 @@ return arg.length; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.lang.reflect.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -44,12 +45,12 @@ field = args[0]; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", "test1"); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", "test2"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ import java.lang.reflect.*; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -48,12 +49,12 @@ field = args[0]; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", "test1"); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", "test2"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -51,22 +52,22 @@ public void method3(int arg1, Object arg2) { } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.reflect; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -51,22 +52,22 @@ public void method3() { } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Monitor_contended01 extends JTTTest implements Runnable { @@ -71,7 +72,7 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Monitor_notowner01 extends JTTTest { @@ -62,7 +63,7 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Object_wait01 extends JTTTest implements Runnable { @@ -57,22 +58,22 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test", 0); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run1() throws Throwable { runTest("test", 1); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run2() throws Throwable { runTest("test", 3); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run3() throws Throwable { runTest("test", 15); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Object_wait02 extends JTTTest implements Runnable { @@ -57,17 +58,17 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test", 0); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run1() throws Throwable { runTest("test", 1); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Object_wait03 extends JTTTest implements Runnable { @@ -63,17 +64,17 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test", 0); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run1() throws Throwable { runTest("test", 1); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run2() throws Throwable { runTest("test", 2); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Object_wait04 extends JTTTest implements Runnable { @@ -67,32 +68,32 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test", 0); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run1() throws Throwable { runTest("test", 1); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run2() throws Throwable { runTest("test", 2); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run3() throws Throwable { runTest("test", 3); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run4() throws Throwable { runTest("test", 4); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run5() throws Throwable { runTest("test", 5); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -59,22 +60,22 @@ } } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Thread_getState02 extends JTTTest { @@ -33,7 +34,7 @@ return new Thread().getState() == Thread.State.NEW; } - @LongTest + @Test public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,8 +26,9 @@ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; //Test all, mainly monitors public class Thread_isInterrupted02 extends JTTTest { @@ -85,12 +86,12 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test", 0, 0); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run1() throws Throwable { runTest("test", 1, 500); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -68,7 +69,7 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -66,7 +67,7 @@ } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; /* */ @@ -66,7 +67,7 @@ } } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Thread_join01 extends JTTTest implements Runnable { @@ -43,7 +44,7 @@ cont = false; } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,8 +27,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Thread_join02 extends JTTTest implements Runnable { @@ -50,7 +51,7 @@ cont = false; } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,8 +27,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Thread_join03 extends JTTTest implements Runnable { @@ -47,7 +48,7 @@ cont = false; } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test"); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Thread_new01 extends JTTTest { @@ -45,27 +46,27 @@ return false; } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public class Thread_new02 extends JTTTest implements Runnable { @@ -51,27 +52,27 @@ // do nothing. } - @LongTest + @Test public void run0() throws Throwable { runTest("test", 0); } - @LongTest + @Test public void run1() throws Throwable { runTest("test", 1); } - @LongTest + @Test public void run2() throws Throwable { runTest("test", 2); } - @LongTest + @Test public void run3() throws Throwable { runTest("test", 3); } - @LongTest + @Test public void run4() throws Throwable { runTest("test", 4); }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,9 @@ */ package com.oracle.graal.jtt.threads; +import org.junit.*; + import com.oracle.graal.jtt.*; -import com.oracle.graal.test.*; public final class Thread_sleep01 extends JTTTest { @@ -35,17 +36,17 @@ return System.currentTimeMillis() - before >= i; } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run0() throws Throwable { runTest("test", 10); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run1() throws Throwable { runTest("test", 20); } - @LongTest(timeout = 20000) + @Test(timeout = 20000) public void run2() throws Throwable { runTest("test", 100); }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Tue Apr 29 18:35:10 2014 +0200 @@ -39,8 +39,8 @@ // @formatter:off - IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, - LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, + IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, IROL, IROR, + LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, LROL, LROR, FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR, DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, INEG, LNEG, INOT, LNOT, @@ -491,6 +491,14 @@ assert asIntReg(src).equals(AMD64.rcx); masm.shrl(asIntReg(dst)); break; + case IROL: + assert asIntReg(src).equals(AMD64.rcx); + masm.roll(asIntReg(dst)); + break; + case IROR: + assert asIntReg(src).equals(AMD64.rcx); + masm.roll(asIntReg(dst)); + break; case LADD: masm.addq(asLongReg(dst), asLongReg(src)); @@ -522,6 +530,14 @@ assert asIntReg(src).equals(AMD64.rcx); masm.shrq(asLongReg(dst)); break; + case LROL: + assert asIntReg(src).equals(AMD64.rcx); + masm.rolq(asLongReg(dst)); + break; + case LROR: + assert asIntReg(src).equals(AMD64.rcx); + masm.rorq(asLongReg(dst)); + break; case FADD: masm.addss(asFloatReg(dst), asFloatReg(src)); @@ -695,6 +711,12 @@ case IUSHR: masm.shrl(asIntReg(dst), crb.asIntConst(src) & 31); break; + case IROL: + masm.roll(asIntReg(dst), crb.asIntConst(src) & 31); + break; + case IROR: + masm.rorl(asIntReg(dst), crb.asIntConst(src) & 31); + break; case LADD: masm.addq(asLongReg(dst), crb.asIntConst(src)); @@ -723,6 +745,12 @@ case LUSHR: masm.shrq(asLongReg(dst), crb.asIntConst(src) & 63); break; + case LROL: + masm.rolq(asLongReg(dst), crb.asIntConst(src) & 31); + break; + case LROR: + masm.rorq(asLongReg(dst), crb.asIntConst(src) & 31); + break; case FADD: masm.addss(asFloatReg(dst), (AMD64Address) crb.asFloatConstRef(src));
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Tue Apr 29 18:35:10 2014 +0200 @@ -132,6 +132,9 @@ default: throw GraalInternalError.shouldNotReachHere(); } + + } else { + throw GraalInternalError.shouldNotReachHere(); } }
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Tue Apr 29 18:35:10 2014 +0200 @@ -480,6 +480,32 @@ } } + @Opcode("ATOMIC_READ_AND_WRITE") + public static class AtomicReadAndWriteOp extends HSAILLIRInstruction { + + private final Kind accessKind; + + @Def protected AllocatableValue result; + @Use({COMPOSITE}) protected HSAILAddressValue address; + @Use({REG, CONST}) protected Value newValue; + + public AtomicReadAndWriteOp(Kind accessKind, AllocatableValue result, HSAILAddressValue address, Value newValue) { + this.accessKind = accessKind; + this.result = result; + this.address = address; + this.newValue = newValue; + } + + public HSAILAddressValue getAddress() { + return address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { + masm.emitAtomicExch(accessKind, result, address.toAddress(), newValue); + } + } + public static class NullCheckOp extends HSAILLIRInstruction { @Use protected Value input;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Tue Apr 29 18:35:10 2014 +0200 @@ -68,7 +68,7 @@ FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR, DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, INEG, LNEG, FNEG, DNEG, INOT, LNOT, - I2L, L2I, I2B, I2C, I2S, + L2I, B2I, S2I, B2L, S2L, I2L, F2D, D2F, I2F, I2D, F2I, D2I, L2F, L2D, F2L, D2L, @@ -572,11 +572,11 @@ case L2I: new Signx(asLongReg(src), asIntReg(dst)).emit(masm); break; - case I2B: + case B2I: new Sll(asIntReg(src), 24, asIntReg(dst)).emit(masm); new Srl(asIntReg(dst), 24, asIntReg(dst)).emit(masm); break; - case I2C: + case S2I: new Sll(asIntReg(src), 16, asIntReg(dst)).emit(masm); new Srl(asIntReg(dst), 16, asIntReg(dst)).emit(masm); break;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Tue Apr 29 18:35:10 2014 +0200 @@ -270,13 +270,16 @@ @Opcode("CMOVE") public static class CondMoveOp extends SPARCLIRInstruction { + private final Kind kind; + @Def({REG, HINT}) protected Value result; @Alive({REG}) protected Value trueValue; @Use({REG, STACK, CONST}) protected Value falseValue; private final ConditionFlag condition; - public CondMoveOp(Variable result, Condition condition, Variable trueValue, Value falseValue) { + public CondMoveOp(Kind kind, Variable result, Condition condition, Variable trueValue, Value falseValue) { + this.kind = kind; this.result = result; this.condition = intCond(condition); this.trueValue = trueValue; @@ -285,20 +288,28 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - cmove(crb, masm, result, false, condition, false, trueValue, falseValue); + // check that we don't overwrite an input operand before it is used. + assert !result.equals(trueValue); + + SPARCMove.move(crb, masm, result, falseValue); + cmove(crb, masm, kind, result, condition, trueValue); } } @Opcode("CMOVE") public static class FloatCondMoveOp extends SPARCLIRInstruction { + private final Kind kind; + @Def({REG}) protected Value result; @Alive({REG}) protected Value trueValue; @Alive({REG}) protected Value falseValue; + private final ConditionFlag condition; private final boolean unorderedIsTrue; - public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { + public FloatCondMoveOp(Kind kind, Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { + this.kind = kind; this.result = result; this.condition = floatCond(condition); this.unorderedIsTrue = unorderedIsTrue; @@ -308,18 +319,12 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - cmove(crb, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue); - } - } + // check that we don't overwrite an input operand before it is used. + assert !result.equals(trueValue); - private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, boolean isFloat, ConditionFlag condition, boolean unorderedIsTrue, Value trueValue, Value falseValue) { - // check that we don't overwrite an input operand before it is used. - assert !result.equals(trueValue); + SPARCMove.move(crb, masm, result, falseValue); + cmove(crb, masm, kind, result, condition, trueValue); - SPARCMove.move(crb, masm, result, falseValue); - cmove(crb, masm, result, condition, trueValue); - - if (isFloat) { if (unorderedIsTrue && !trueOnUnordered(condition)) { // cmove(crb, masm, result, ConditionFlag.Parity, trueValue); throw GraalInternalError.unimplemented(); @@ -330,18 +335,20 @@ } } - private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, ConditionFlag cond, Value other) { + private static void cmove(CompilationResultBuilder crb, SPARCMacroAssembler masm, Kind kind, Value result, ConditionFlag cond, Value other) { if (!isRegister(other)) { SPARCMove.move(crb, masm, result, other); - throw new InternalError("result should be scratch"); + throw GraalInternalError.shouldNotReachHere("result should be scratch"); } assert !asRegister(other).equals(asRegister(result)) : "other already overwritten by previous move"; - switch (other.getKind()) { + switch (kind) { case Int: - // XXX CC depends on compare new Movcc(cond, CC.Icc, asRegister(other), asRegister(result)).emit(masm); break; case Long: + case Object: + new Movcc(cond, CC.Xcc, asRegister(other), asRegister(result)).emit(masm); + break; default: throw GraalInternalError.shouldNotReachHere(); }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.lir.*; /** @@ -33,7 +34,7 @@ * * <pre> * Base Contents - * + * * : : ----- * caller | incoming overflow argument n | ^ * frame : ... : | positive @@ -88,8 +89,7 @@ @Override protected int alignFrameSize(int size) { - int x = size + (target.stackAlignment - 1); - return (x / target.stackAlignment) * target.stackAlignment; + return NumUtil.roundUp(size, target.stackAlignment); } @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Tue Apr 29 18:35:10 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,32 +23,14 @@ package com.oracle.graal.lir.sparc; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import static com.oracle.graal.sparc.SPARC.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CompilationResult.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCAssembler.Add; -import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf; -import com.oracle.graal.asm.sparc.SPARCAssembler.Ldf; -import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsb; -import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsh; -import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw; -import com.oracle.graal.asm.sparc.SPARCAssembler.Lduh; -import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx; -import com.oracle.graal.asm.sparc.SPARCAssembler.Membar; -import com.oracle.graal.asm.sparc.SPARCAssembler.Rdpc; -import com.oracle.graal.asm.sparc.SPARCAssembler.Stb; -import com.oracle.graal.asm.sparc.SPARCAssembler.Sth; -import com.oracle.graal.asm.sparc.SPARCAssembler.Stw; -import com.oracle.graal.asm.sparc.SPARCAssembler.Stx; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cas; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Casx; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Clr; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setuw; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; @@ -154,32 +136,33 @@ @Override public void emitMemAccess(SPARCMacroAssembler masm) { - SPARCAddress addr = address.toAddress(); + final SPARCAddress addr = address.toAddress(); + final Register dst = asRegister(result); switch (kind) { case Boolean: case Byte: - new Ldsb(addr, asRegister(result)).emit(masm); + new Ldsb(addr, dst).emit(masm); break; case Short: - new Ldsh(addr, asRegister(result)).emit(masm); + new Ldsh(addr, dst).emit(masm); break; case Char: - new Lduh(addr, asRegister(result)).emit(masm); + new Lduh(addr, dst).emit(masm); break; case Int: - new Ldsw(addr, asRegister(result)).emit(masm); + new Ldsw(addr, dst).emit(masm); break; case Long: - new Ldx(addr, asRegister(result)).emit(masm); + new Ldx(addr, dst).emit(masm); break; case Float: - new Ldf(addr, asRegister(result)).emit(masm); + new Ldf(addr, dst).emit(masm); break; case Double: - new Lddf(addr, asRegister(result)).emit(masm); + new Lddf(addr, dst).emit(masm); break; case Object: - new Ldx(addr, asRegister(result)).emit(masm); + new Ldx(addr, dst).emit(masm); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -208,6 +191,26 @@ } } + public static class LoadDataAddressOp extends SPARCLIRInstruction { + + @Def({REG}) protected AllocatableValue result; + private final byte[] data; + + public LoadDataAddressOp(AllocatableValue result, byte[] data) { + this.result = result; + this.data = data; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + RawData rawData = new RawData(data, 16); + SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(rawData); + assert addr == masm.getPlaceholder(); + final boolean forceRelocatable = true; + new Setx(0, asRegister(result), forceRelocatable).emit(masm); + } + } + public static class MembarOp extends SPARCLIRInstruction { private final int barriers; @@ -395,19 +398,25 @@ } private static void reg2reg(SPARCAssembler masm, Value result, Value input) { - if (asRegister(input).equals(asRegister(result))) { + final Register src = asRegister(input); + final Register dst = asRegister(result); + if (src.equals(dst)) { return; } switch (input.getKind()) { case Int: case Long: case Object: - new Mov(asRegister(input), asRegister(result)).emit(masm); + new Mov(src, dst).emit(masm); break; case Float: + new Fmovs(src, dst).emit(masm); + break; case Double: + new Fmovd(src, dst).emit(masm); + break; default: - throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind()); + throw GraalInternalError.shouldNotReachHere(); } } @@ -423,7 +432,11 @@ new Stx(src, dst).emit(masm); break; case Float: + new Stf(src, dst).emit(masm); + break; case Double: + new Stdf(src, dst).emit(masm); + break; default: throw GraalInternalError.shouldNotReachHere(); } @@ -461,7 +474,7 @@ } } break; - case Long: { + case Long: if (crb.codeCache.needsDataPatch(input)) { crb.recordInlineDataInCode(input); new Setx(input.asLong(), asRegister(result), true).emit(masm); @@ -473,8 +486,10 @@ } } break; - } - case Object: { + case Float: + new Ldf((SPARCAddress) crb.asFloatConstRef(input), asFloatReg(result)).emit(masm); + break; + case Object: if (input.isNull()) { new Clr(asRegister(result)).emit(masm); } else if (crb.target.inlineObjects) { @@ -488,7 +503,6 @@ throw GraalInternalError.shouldNotReachHere("the patched offset might be too big for the load"); } break; - } default: throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind()); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.sparc; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.SaveRegistersOp; +import com.oracle.graal.lir.asm.*; + +/** + * Saves registers to stack slots. + */ +@Opcode("SAVE_REGISTER") +public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp { + + /** + * The registers (potentially) saved by this operation. + */ + protected final Register[] savedRegisters; + + /** + * The slots to which the registers are saved. + */ + @Def(STACK) protected final StackSlot[] slots; + + /** + * Specifies if {@link #remove(Set)} should have an effect. + */ + protected final boolean supportsRemove; + + /** + * + * @param savedRegisters the registers saved by this operation which may be subject to + * {@linkplain #remove(Set) pruning} + * @param slots the slots to which the registers are saved + * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned} + */ + public SPARCSaveRegistersOp(Register[] savedRegisters, StackSlot[] slots, boolean supportsRemove) { + this.savedRegisters = savedRegisters; + this.slots = slots; + this.supportsRemove = supportsRemove; + } + + private static void saveRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, StackSlot result, Register register) { + RegisterValue input = register.asValue(result.getKind()); + SPARCMove.move(crb, masm, result, input); + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + saveRegister(crb, masm, slots[i], savedRegisters[i]); + } + } + } + + public StackSlot[] getSlots() { + return slots; + } + + public boolean supportsRemove() { + return supportsRemove; + } + + public int remove(Set<Register> doNotSave) { + if (!supportsRemove) { + throw new UnsupportedOperationException(); + } + return prune(doNotSave, savedRegisters); + } + + static int prune(Set<Register> toRemove, Register[] registers) { + int pruned = 0; + for (int i = 0; i < registers.length; i++) { + if (registers[i] != null) { + if (toRemove.contains(registers[i])) { + registers[i] = null; + pruned++; + } + } + } + return pruned; + } + + public RegisterSaveLayout getMap(FrameMap frameMap) { + int total = 0; + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + total++; + } + } + Register[] keys = new Register[total]; + int[] values = new int[total]; + if (total != 0) { + int mapIndex = 0; + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + keys[mapIndex] = savedRegisters[i]; + values[mapIndex] = frameMap.indexForStackSlot(slots[i]); + mapIndex++; + } + } + assert mapIndex == total; + } + return new RegisterSaveLayout(keys, values); + } +}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Tue Apr 29 18:35:10 2014 +0200 @@ -92,14 +92,8 @@ compilationResult.setTotalFrameSize(frameSize); } - private static final CompilationResult.Mark[] NO_REFS = {}; - public CompilationResult.Mark recordMark(Object id) { - return compilationResult.recordMark(asm.position(), id, NO_REFS); - } - - public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) { - return compilationResult.recordMark(asm.position(), id, references); + return compilationResult.recordMark(asm.position(), id); } public void blockComment(String s) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Apr 29 18:35:10 2014 +0200 @@ -48,7 +48,7 @@ /** * This class traverses the HIR instructions and generates LIR instructions from them. */ -public abstract class LIRGenerator implements ArithmeticLIRGenerator, LIRGeneratorTool, PlatformKindTool { +public abstract class LIRGenerator implements LIRGeneratorTool, PlatformKindTool { public static class Options { // @formatter:off @@ -62,9 +62,7 @@ private final CodeGenProviders providers; private final CallingConvention cc; - protected AbstractBlock<?> currentBlock; - public final int traceLevel; - public final boolean printIRWithLIR; + private AbstractBlock<?> currentBlock; /** * Handle for an operation that loads a constant into a variable. The operation starts in the @@ -173,8 +171,6 @@ this.res = res; this.providers = providers; this.cc = cc; - this.traceLevel = Options.TraceLIRGeneratorLevel.getValue(); - this.printIRWithLIR = Options.PrintIRWithLIR.getValue(); } /** @@ -272,7 +268,7 @@ } public void append(LIRInstruction op) { - if (printIRWithLIR && !TTY.isSuppressed()) { + if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { TTY.println(op.toStringWithIdPrefix()); TTY.println(); } @@ -289,7 +285,7 @@ } public final void doBlockStart(AbstractBlock<?> block) { - if (printIRWithLIR) { + if (Options.PrintIRWithLIR.getValue()) { TTY.print(block.toString()); } @@ -301,20 +297,20 @@ append(new LabelOp(new Label(block.getId()), block.isAligned())); - if (traceLevel >= 1) { + if (Options.TraceLIRGeneratorLevel.getValue() >= 1) { TTY.println("BEGIN Generating LIR for block B" + block.getId()); } } public final void doBlockEnd(AbstractBlock<?> block) { - if (traceLevel >= 1) { + if (Options.TraceLIRGeneratorLevel.getValue() >= 1) { TTY.println("END Generating LIR for block B" + block.getId()); } currentBlock = null; - if (printIRWithLIR) { + if (Options.PrintIRWithLIR.getValue()) { TTY.println(); } }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,13 +22,21 @@ */ package com.oracle.graal.lir.gen; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.calc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.compiler.common.spi.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.gen.LIRGenerator.*; public interface LIRGeneratorTool extends ArithmeticLIRGenerator { + CodeGenProviders getProviders(); + TargetDescription target(); MetaAccessProvider getMetaAccess(); @@ -37,6 +45,20 @@ ForeignCallsProvider getForeignCalls(); + AbstractBlock<?> getCurrentBlock(); + + LIRGenerationResult getResult(); + + boolean hasBlockEnd(AbstractBlock<?> block); + + void doBlockStart(AbstractBlock<?> block); + + void doBlockEnd(AbstractBlock<?> block); + + Map<Constant, LoadConstant> getConstantLoads(); + + void setConstantLoads(Map<Constant, LoadConstant> constantLoads); + Value emitLoad(PlatformKind kind, Value address, LIRFrameState state); void emitStore(PlatformKind kind, Value address, Value input, LIRFrameState state); @@ -65,7 +87,7 @@ void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state); - Value emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args); + Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args); /** * Checks whether the supplied constant can be used without loading it into a register for most @@ -81,9 +103,9 @@ RegisterAttributes attributes(Register register); - AllocatableValue newVariable(PlatformKind kind); + Variable newVariable(PlatformKind kind); - AllocatableValue emitMove(Value input); + Variable emitMove(Value input); void emitMove(AllocatableValue dst, Value src); @@ -116,4 +138,62 @@ * correct location. */ void emitReturn(Value input); + + AllocatableValue asAllocatable(Value value); + + Variable load(Value value); + + Value loadNonConst(Value value); + + /** + * Returns true if the redundant move elimination optimization should be done after register + * allocation. + */ + boolean canEliminateRedundantMoves(); + + /** + * Determines if only oop maps are required for the code generated from the LIR. + */ + boolean needOnlyOopMaps(); + + /** + * Gets the ABI specific operand used to return a value of a given kind from a method. + * + * @param kind the kind of value being returned + * @return the operand representing the ABI defined location used return a value of kind + * {@code kind} + */ + AllocatableValue resultOperandFor(Kind kind); + + void append(LIRInstruction op); + + void emitJump(LabelRef label); + + void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, + double trueDestinationProbability); + + void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability); + + void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability); + + Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue); + + Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue); + + void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value); + + void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget); + + CallingConvention getCallingConvention(); + + void emitBitCount(Variable result, Value operand); + + void emitBitScanForward(Variable result, Value operand); + + void emitBitScanReverse(Variable result, Value operand); + + void emitByteSwap(Variable result, Value operand); + + void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length); + }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Tue Apr 29 18:35:10 2014 +0200 @@ -114,7 +114,7 @@ FrameState exitState = exit.stateAfter(); if (exitState != null) { exitState.applyToVirtual(v -> { - if (v.usages().filter(n -> nodes.isMarked(n) && !(n instanceof VirtualState && exitState.isPartOfThisState((VirtualState) n))).isEmpty()) { + if (v.usages().filter(n -> nodes.isMarked(n) && n != exit).isEmpty()) { nodes.clear(v); } });
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryLogicNode.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes; - -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; - -public abstract class BinaryLogicNode extends LogicNode implements LIRLowerable, MemoryArithmeticLIRLowerable { - - @Input private ValueNode x; - @Input private ValueNode y; - - public ValueNode x() { - return x; - } - - public ValueNode y() { - return y; - } - - protected void setX(ValueNode x) { - updateUsages(this.x, x); - this.x = x; - } - - protected void setY(ValueNode y) { - updateUsages(this.y, y); - this.y = y; - } - - public BinaryLogicNode(ValueNode x, ValueNode y) { - assert x != null && y != null && x.getKind() == y.getKind(); - this.x = x; - this.y = y; - } - - @Override - public boolean verify() { - assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp()); - return super.verify(); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - return false; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodes.spi.*; + +public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable { + + @Input private ValueNode x; + @Input private ValueNode y; + + public ValueNode x() { + return x; + } + + public ValueNode y() { + return y; + } + + protected void setX(ValueNode x) { + updateUsages(this.x, x); + this.x = x; + } + + protected void setY(ValueNode y) { + updateUsages(this.y, y); + this.y = y; + } + + public BinaryOpLogicNode(ValueNode x, ValueNode y) { + assert x != null && y != null && x.getKind() == y.getKind(); + this.x = x; + this.y = y; + } + + public abstract TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY); + + @Override + public boolean verify() { + assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp()); + return super.verify(); + } + + @Override + public Node canonical(CanonicalizerTool tool) { + switch (evaluate(tool.getConstantReflection(), x(), y())) { + case FALSE: + return LogicConstantNode.contradiction(graph()); + case TRUE: + return LogicConstantNode.tautology(graph()); + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + } +}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Tue Apr 29 18:35:10 2014 +0200 @@ -95,8 +95,8 @@ this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings); this.rethrowException = rethrowException; this.duringCall = duringCall; - assert !rethrowException || stackSize == 1 : "must have exception on top of the stack"; - assert values.size() - localsSize - stackSize == monitorIds.size(); + assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack"; + assert this.locksSize() == this.monitorIds.size(); } /** @@ -220,6 +220,19 @@ * correctly in slot encoding: a long or double will be followed by a null slot. */ public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) { + return duplicateModified(newBci, method, newRethrowException, popKind, pushedValues); + } + + /** + * Creates a copy of this frame state with one stack element of type popKind popped from the + * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted + * correctly in slot encoding: a long or double will be followed by a null slot. + */ + public FrameState duplicateModified(Kind popKind, ValueNode... pushedValues) { + return duplicateModified(bci, method, rethrowException, popKind, pushedValues); + } + + private FrameState duplicateModified(int newBci, ResolvedJavaMethod newMethod, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) { ArrayList<ValueNode> copy = new ArrayList<>(values.subList(0, localsSize + stackSize)); if (popKind != Kind.Void) { if (stackAt(stackSize() - 1) == null) { @@ -238,7 +251,7 @@ int newStackSize = copy.size() - localsSize; copy.addAll(values.subList(localsSize + stackSize, values.size())); - FrameState other = graph().add(new FrameState(method, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings)); + FrameState other = graph().add(new FrameState(newMethod, newBci, copy, localsSize, newStackSize, newRethrowException, false, monitorIds, virtualObjectMappings)); other.setOuterFrameState(outerFrameState()); return other; } @@ -386,7 +399,7 @@ @Override public boolean verify() { - assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks"); + assertTrue(locksSize() == monitorIds.size(), "mismatch in number of locks"); for (ValueNode value : values) { assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes"); assertTrue(value == null || value instanceof VirtualObjectNode || (value.getKind() != Kind.Void), "unexpected value: %s", value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -107,7 +107,8 @@ } else if (condition() instanceof LogicConstantNode) { LogicConstantNode c = (LogicConstantNode) condition(); if (c.getValue() != negated) { - return graph().start(); + this.replaceAtUsages(null); + return null; } } return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -77,7 +77,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (getGuard() == graph().start() || getGuard() == null) { + if (getGuard() == null) { if (stamp().equals(object().stamp())) { return object(); } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -51,6 +51,18 @@ return condition; } + public boolean isNegated() { + return negated; + } + + public DeoptimizationReason getReason() { + return reason; + } + + public DeoptimizationAction getAction() { + return action; + } + /** * Constructor for {@link #guardingNonNull(Object)} node intrinsic. */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -34,7 +34,6 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; @@ -43,7 +42,7 @@ * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome * of a comparison. */ -public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable { +public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable { @Successor private BeginNode trueSuccessor; @Successor private BeginNode falseSuccessor; @@ -132,11 +131,6 @@ } @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - return gen.emitIfMemory(this, access); - } - - @Override public boolean verify() { assertTrue(condition() != null, "missing condition"); assertTrue(trueSuccessor() != null, "missing trueSuccessor");
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -43,6 +43,6 @@ @Override public String targetName() { - return "Indirect#" + ((JavaMethod) target()).getName(); + return MetaUtil.format("Indirect#%h.%n", target()); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -37,7 +37,7 @@ private static final double EXCEPTION_PROBA = 1e-5; @Successor private BeginNode next; - @Successor private DispatchBeginNode exceptionEdge; + @Successor private BeginNode exceptionEdge; @Input(InputType.Extension) private CallTargetNode callTarget; @Input(InputType.State) private FrameState stateDuring; @Input(InputType.State) private FrameState stateAfter; @@ -47,7 +47,7 @@ private boolean useForInlining; private double exceptionProbability; - public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci) { + public InvokeWithExceptionNode(CallTargetNode callTarget, BeginNode exceptionEdge, int bci) { super(callTarget.returnStamp()); this.exceptionEdge = exceptionEdge; this.bci = bci; @@ -57,11 +57,11 @@ this.exceptionProbability = EXCEPTION_PROBA; } - public DispatchBeginNode exceptionEdge() { + public BeginNode exceptionEdge() { return exceptionEdge; } - public void setExceptionEdge(DispatchBeginNode x) { + public void setExceptionEdge(BeginNode x) { updatePredecessor(exceptionEdge, x); exceptionEdge = x; }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -155,7 +155,7 @@ return; } for (PhiNode phi : phis()) { - if (phi.usages().filter(isNotA(FrameState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) { + if (phi.usages().filter(isNotA(VirtualState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) { return; } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.nodes.spi.*; + +public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable { + + @Input private ValueNode object; + + public ValueNode object() { + return object; + } + + protected void setX(ValueNode object) { + updateUsages(this.object, object); + this.object = object; + } + + public UnaryOpLogicNode(ValueNode object) { + assert object != null; + this.object = object; + } + + public abstract TriState evaluate(ValueNode forObject); + + @Override + public void generate(NodeLIRBuilderTool gen) { + } +}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java Tue Apr 29 18:35:10 2014 +0200 @@ -45,6 +45,10 @@ public abstract void applyToNonVirtual(NodeClosure<? super ValueNode> closure); + /** + * Performs a <b>pre-order</b> iteration over all elements reachable from this state that are a + * subclass of {@link VirtualState}. + */ public abstract void applyToVirtual(VirtualClosure closure); public abstract boolean isPartOfThisState(VirtualState state);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -93,13 +92,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitAnd(builder.operand(x()), builder.operand(y()))); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitAndMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -30,7 +30,7 @@ /** * The {@code LogicNode} class definition. */ -public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode { +public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode { /** * Constructs a new logic operation node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.graph.*; @@ -35,7 +36,7 @@ * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed * into variants that do not materialize the value (CompareIf, CompareGuard...) */ -public abstract class CompareNode extends BinaryLogicNode implements Canonicalizable { +public abstract class CompareNode extends BinaryOpLogicNode { /** * Constructs a new Compare instruction. @@ -90,9 +91,18 @@ } @Override + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (x().isConstant() && y().isConstant()) { + return TriState.get(condition().foldCondition(x().asConstant(), y().asConstant(), constantReflection, unorderedIsTrue())); + } + return TriState.UNKNOWN; + } + + @Override public Node canonical(CanonicalizerTool tool) { - if (x().isConstant() && y().isConstant() && tool.getMetaAccess() != null) { - return LogicConstantNode.forBoolean(condition().foldCondition(x().asConstant(), y().asConstant(), tool.getConstantReflection(), unorderedIsTrue()), graph()); + Node result = super.canonical(tool); + if (result != this) { + return result; } if (x().isConstant()) { if (y() instanceof ConditionalNode) { @@ -110,7 +120,7 @@ if (x() instanceof ConvertNode && y() instanceof ConvertNode) { ConvertNode convertX = (ConvertNode) x(); ConvertNode convertY = (ConvertNode) y(); - if (convertX.isLossless() && convertY.isLossless() && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) { + if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) { setX(convertX.getInput()); setY(convertY.getInput()); } @@ -132,8 +142,8 @@ return this; } - private static ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) { - if (convert.isLossless()) { + private ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) { + if (convert.preservesOrder(condition())) { Constant reverseConverted = convert.reverse(constant); if (convert.convert(reverseConverted).equals(constant)) { return ConstantNode.forPrimitive(convert.getInput().stamp(), reverseConverted, convert.graph());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.nodes.*; @@ -47,8 +48,23 @@ public abstract Constant reverse(Constant c); + /** + * Check whether a conversion is lossless. + * + * @return true iff reverse(convert(c)) == c for all c + */ public abstract boolean isLossless(); + /** + * Check whether a conversion preserves comparison order. + * + * @param op a comparison operator + * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2 + */ + public boolean preservesOrder(Condition op) { + return isLossless(); + } + @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 1;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "+") @@ -85,13 +84,4 @@ } return false; } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitAddMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; -public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { +public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable { private final boolean isStrictFP;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -30,14 +30,13 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; /** * A {@code FloatConvert} converts between integers and floating point numbers according to Java * semantics. */ -public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { +public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable { private final FloatConvert op; @@ -167,12 +166,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitFloatConvert(op, builder.operand(getInput()))); } - - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitFloatConvertMemory(getOp(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "/") @@ -61,13 +60,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitDiv(builder.operand(x()), builder.operand(y()), null)); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitDivMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,17 +22,20 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "==") public final class FloatEqualsNode extends CompareNode { /** * Constructs a new floating point equality comparison node. - * + * * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction */ @@ -51,4 +54,18 @@ public boolean unorderedIsTrue() { return false; } + + @Override + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (forX.stamp() instanceof FloatStamp && forY.stamp() instanceof FloatStamp) { + FloatStamp xStamp = (FloatStamp) forX.stamp(); + FloatStamp yStamp = (FloatStamp) forY.stamp(); + if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) { + return TriState.TRUE; + } else if (xStamp.alwaysDistinct(yStamp)) { + return TriState.FALSE; + } + } + return super.evaluate(constantReflection, forX, forY); + } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,11 +22,13 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "<") public final class FloatLessThanNode extends CompareNode { @@ -35,7 +37,7 @@ /** * Constructs a new floating point comparison node. - * + * * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction * @param unorderedIsTrue whether a comparison that is undecided (involving NaNs, etc.) leads to @@ -59,10 +61,10 @@ } @Override - public Node canonical(CanonicalizerTool tool) { - if (x() == y() && !unorderedIsTrue()) { - return LogicConstantNode.contradiction(graph()); + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && !unorderedIsTrue()) { + return TriState.FALSE; } - return super.canonical(tool); + return super.evaluate(constantReflection, forX, forY); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "*") @@ -71,13 +70,4 @@ } builder.setResult(this, gen.emitMul(op1, op2)); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitMulMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "%") @@ -61,13 +60,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitRem(builder.operand(x()), builder.operand(y()), null)); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitRemMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "-") @@ -80,13 +79,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y()))); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitSubMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -102,13 +101,4 @@ } builder.setResult(this, gen.emitAdd(op1, op2)); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitAddMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { +public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable { public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) { super(stamp, x, y);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,18 +23,20 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "|<|") public final class IntegerBelowThanNode extends CompareNode { /** * Constructs a new unsigned integer comparison node. - * + * * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction */ @@ -55,28 +57,33 @@ } @Override - public Node canonical(CanonicalizerTool tool) { - if (x() == y()) { - return LogicConstantNode.contradiction(graph()); - } else { - if (x().isConstant() && x().asConstant().asLong() == 0) { - // 0 |<| y is the same as 0 != y - return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y()))); - } - - if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) { - IntegerStamp xStamp = (IntegerStamp) x().stamp(); - IntegerStamp yStamp = (IntegerStamp) y().stamp(); - if (yStamp.isPositive()) { - if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) { - return LogicConstantNode.tautology(graph()); - } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) { - return LogicConstantNode.contradiction(graph()); - } + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { + return TriState.FALSE; + } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { + IntegerStamp xStamp = (IntegerStamp) forX.stamp(); + IntegerStamp yStamp = (IntegerStamp) forY.stamp(); + if (yStamp.isPositive()) { + if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) { + return TriState.TRUE; + } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) { + return TriState.FALSE; } } } + return super.evaluate(constantReflection, forX, forY); + } - return super.canonical(tool); + @Override + public Node canonical(CanonicalizerTool tool) { + Node result = super.canonical(tool); + if (result != this) { + return result; + } + if (x().isConstant() && x().asConstant().asLong() == 0) { + // 0 |<| y is the same as 0 != y + return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y()))); + } + return this; } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -31,7 +31,7 @@ /** * An {@code IntegerConvert} converts an integer to an integer of different width. */ -public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable { +public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable { private final int resultBits;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; @@ -35,7 +36,7 @@ /** * Constructs a new integer equality comparison node. - * + * * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction */ @@ -71,24 +72,28 @@ } @Override + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { + return TriState.TRUE; + } else if (forX.stamp().alwaysDistinct(forY.stamp())) { + return TriState.FALSE; + } + return super.evaluate(constantReflection, forX, forY); + } + + @Override public Node canonical(CanonicalizerTool tool) { - if (GraphUtil.unproxify(x()) == GraphUtil.unproxify(y())) { - return LogicConstantNode.tautology(graph()); - } else if (x().stamp().alwaysDistinct(y().stamp())) { - return LogicConstantNode.contradiction(graph()); - } - - ValueNode result = canonicalizeSymmetric(x(), y()); - if (result != null) { + Node result = super.canonical(tool); + if (result != this) { return result; } - result = canonicalizeSymmetric(y(), x()); - if (result != null) { + result = canonicalizeSymmetric(x(), y()); + if (result != this) { return result; } - return super.canonical(tool); + return canonicalizeSymmetric(y(), x()); } private ValueNode canonicalizeSymmetric(ValueNode x, ValueNode y) { @@ -133,6 +138,6 @@ } } } - return null; + return this; } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,18 +23,20 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "<") public final class IntegerLessThanNode extends CompareNode { /** * Constructs a new integer comparison node. - * + * * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction */ @@ -71,22 +73,32 @@ } @Override + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { + return TriState.FALSE; + } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { + IntegerStamp xStamp = (IntegerStamp) forX.stamp(); + IntegerStamp yStamp = (IntegerStamp) forY.stamp(); + if (xStamp.upperBound() < yStamp.lowerBound()) { + return TriState.TRUE; + } else if (xStamp.lowerBound() >= yStamp.upperBound()) { + return TriState.FALSE; + } + } + return super.evaluate(constantReflection, forX, forY); + } + + @Override public Node canonical(CanonicalizerTool tool) { - if (x() == y()) { - return LogicConstantNode.contradiction(graph()); + Node result = super.canonical(tool); + if (result != this) { + return result; } if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) { - IntegerStamp xStamp = (IntegerStamp) x().stamp(); - IntegerStamp yStamp = (IntegerStamp) y().stamp(); - if (xStamp.upperBound() < yStamp.lowerBound()) { - return LogicConstantNode.tautology(graph()); - } else if (xStamp.lowerBound() >= yStamp.upperBound()) { - return LogicConstantNode.contradiction(graph()); - } - if (IntegerStamp.sameSign(xStamp, yStamp)) { + if (IntegerStamp.sameSign((IntegerStamp) x().stamp(), (IntegerStamp) y().stamp())) { return graph().unique(new IntegerBelowThanNode(x(), y())); } } - return super.canonical(tool); + return this; } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "*") @@ -86,13 +85,4 @@ } builder.setResult(this, gen.emitMul(op1, op2)); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitMulMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -122,13 +121,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitSub(builder.operand(x()), builder.operand(y()))); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitSubMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,9 +22,9 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; /** @@ -32,7 +32,7 @@ * expression "(x & y) == 0", meaning that it will return true if (and only if) no bit is set in * both x and y. */ -public class IntegerTestNode extends BinaryLogicNode implements Canonicalizable { +public class IntegerTestNode extends BinaryOpLogicNode { /** * Constructs a new Test instruction. @@ -45,19 +45,19 @@ } @Override - public Node canonical(CanonicalizerTool tool) { - if (x().isConstant() && y().isConstant()) { - return LogicConstantNode.forBoolean((x().asConstant().asLong() & y().asConstant().asLong()) == 0, graph()); + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (forX.isConstant() && forY.isConstant()) { + return TriState.get((forX.asConstant().asLong() & forY.asConstant().asLong()) == 0); } if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) { - IntegerStamp xStamp = (IntegerStamp) x().stamp(); - IntegerStamp yStamp = (IntegerStamp) y().stamp(); + IntegerStamp xStamp = (IntegerStamp) forX.stamp(); + IntegerStamp yStamp = (IntegerStamp) forY.stamp(); if ((xStamp.upMask() & yStamp.upMask()) == 0) { - return LogicConstantNode.tautology(graph()); + return TriState.TRUE; } else if ((xStamp.downMask() & yStamp.downMask()) != 0) { - return LogicConstantNode.contradiction(graph()); + return TriState.FALSE; } } - return this; + return TriState.UNKNOWN; } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; @@ -33,21 +34,15 @@ /** * An IsNullNode will be true if the supplied value is null, and false if it is non-null. */ -public final class IsNullNode extends LogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable { - - @Input private ValueNode object; - - public ValueNode object() { - return object; - } +public final class IsNullNode extends UnaryOpLogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable { /** * Constructs a new IsNullNode instruction. - * + * * @param object the instruction producing the object to check against null */ public IsNullNode(ValueNode object) { - this.object = object; + super(object); } @Override @@ -64,20 +59,31 @@ @Override public Node canonical(CanonicalizerTool tool) { - Constant constant = object().asConstant(); - if (constant != null) { - assert constant.getKind() == Kind.Object; - return LogicConstantNode.forBoolean(constant.isNull(), graph()); - } - if (StampTool.isObjectNonNull(object.stamp())) { - return LogicConstantNode.contradiction(graph()); + switch (evaluate(object())) { + case FALSE: + return LogicConstantNode.contradiction(graph()); + case TRUE: + return LogicConstantNode.tautology(graph()); } return this; } @Override + public TriState evaluate(ValueNode forObject) { + Constant constant = forObject.asConstant(); + if (constant != null) { + assert constant.getKind() == Kind.Object; + return TriState.get(constant.isNull()); + } + if (StampTool.isObjectNonNull(forObject.stamp())) { + return TriState.FALSE; + } + return TriState.UNKNOWN; + } + + @Override public void virtualize(VirtualizerTool tool) { - if (tool.getObjectState(object) != null) { + if (tool.getObjectState(object()) != null) { tool.replaceWithValue(LogicConstantNode.contradiction(graph())); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -109,13 +108,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitNarrow(builder.operand(getInput()), getResultBits())); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitNarrowMemory(getResultBits(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,19 +23,21 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "==") public final class ObjectEqualsNode extends CompareNode implements Virtualizable { /** * Constructs a new object equality comparison node. - * + * * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction */ @@ -56,21 +58,28 @@ } @Override + public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) { + if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { + return TriState.TRUE; + } else if (forX.stamp().alwaysDistinct(forY.stamp())) { + return TriState.FALSE; + } else { + return super.evaluate(constantReflection, forX, forY); + } + } + + @Override public Node canonical(CanonicalizerTool tool) { - if (x() == y()) { - return LogicConstantNode.tautology(graph()); + Node result = super.canonical(tool); + if (result != this) { + return result; } - if (StampTool.isObjectAlwaysNull(x())) { return graph().unique(new IsNullNode(y())); } else if (StampTool.isObjectAlwaysNull(y())) { return graph().unique(new IsNullNode(x())); } - if (x().stamp().alwaysDistinct(y().stamp())) { - return LogicConstantNode.contradiction(graph()); - } - - return super.canonical(tool); + return this; } private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -78,13 +77,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitOr(builder.operand(x()), builder.operand(y()))); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitOrMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; /** @@ -37,7 +36,7 @@ * of a primitive value to some other incompatible stamp. The new stamp must have the same width as * the old stamp. */ -public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { +public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable { @Input private ValueNode value; @@ -109,15 +108,6 @@ builder.setResult(this, gen.emitReinterpret(kind, builder.operand(value()))); } - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitReinterpretMemory(stamp(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } - public static ValueNode reinterpret(Kind toKind, ValueNode value) { return value.graph().unique(new ReinterpretNode(toKind, value)); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -110,13 +109,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitSignExtend(builder.operand(getInput()), getInputBits(), getResultBits())); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitSignExtendMemory(access, getInputBits(), getResultBits()); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -77,13 +76,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitXor(builder.operand(x()), builder.operand(y()))); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitXorMemory(x(), y(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,12 +23,12 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -65,6 +65,19 @@ } @Override + public boolean preservesOrder(Condition op) { + switch (op) { + case GE: + case GT: + case LE: + case LT: + return false; + default: + return true; + } + } + + @Override public Node canonical(CanonicalizerTool tool) { ValueNode ret = canonicalConvert(); if (ret != null) { @@ -103,13 +116,4 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitZeroExtend(builder.operand(getInput()), getInputBits(), getResultBits())); } - - @Override - public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { - Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access); - if (result != null) { - gen.setResult(this, result); - } - return result != null; - } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Apr 29 18:35:10 2014 +0200 @@ -25,8 +25,8 @@ import java.util.*; import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; public final class Block extends AbstractBlockBase<Block> { @@ -67,7 +67,8 @@ } public boolean isExceptionEntry() { - return getBeginNode() instanceof ExceptionObjectNode; + Node predecessor = getBeginNode().predecessor(); + return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge(); } public Block getFirstPredecessor() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -30,7 +30,7 @@ * This node can be used to add a counter to the code that will estimate the dynamic number of calls * by adding an increment to the compiled code. This should of course only be used for * debugging/testing purposes. - * + * * A unique counter will be created for each unique name passed to the constructor. Depending on the * value of withContext, the name of the root method is added to the counter's name. */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -38,8 +38,8 @@ @NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}") public final class AddLocationNode extends LocationNode implements Canonicalizable { - @Input private ValueNode x; - @Input private ValueNode y; + @Input(InputType.Association) private ValueNode x; + @Input(InputType.Association) private ValueNode y; protected LocationNode getX() { return (LocationNode) x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,12 +22,13 @@ */ package com.oracle.graal.nodes.extended; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; /** * A node that may be guarded by a {@linkplain GuardingNode guarding node}. */ -public interface GuardedNode { +public interface GuardedNode extends NodeInterface { GuardingNode getGuard();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Tue Apr 29 18:35:10 2014 +0200 @@ -40,7 +40,7 @@ /** * This method is used to determine which memory location is killed by this node. Returning * the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory locations. - * + * * @return the identity of the location killed by this node. */ LocationIdentity getLocationIdentity(); @@ -53,7 +53,7 @@ * This method is used to determine which set of memory locations is killed by this node. * Returning the special value {@link LocationIdentity#ANY_LOCATION} will kill all memory * locations. - * + * * @return the identities of all locations killed by this node. */ LocationIdentity[] getLocationIdentities();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,12 +22,13 @@ */ package com.oracle.graal.nodes.extended; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; /** * This interface marks nodes that are part of the memory graph. */ -public interface MemoryNode { +public interface MemoryNode extends NodeInterface { ValueNode asNode();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,13 +22,9 @@ */ package com.oracle.graal.nodes.java; -import java.util.*; - -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @@ -37,6 +33,7 @@ * The entry to an exception handler with the exception coming from a call (as opposed to a local * throw instruction or implicit exception). */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}) public class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, MemoryCheckpoint.Single { public ExceptionObjectNode(MetaAccessProvider metaAccess) { @@ -49,56 +46,13 @@ } @Override - public void simplify(SimplifierTool tool) { - // - } - - private boolean isLowered() { - return (stamp() == StampFactory.forVoid()); - } - - /** - * The frame state upon entry to an exception handler is such that it is a - * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly - * the exception object (per the JVM spec) to rethrow. This means that the code creating this - * state (i.e. the {@link LoadExceptionObjectNode}) cannot cause a deoptimization as the - * runtime/interpreter would not have a valid location for the exception object to be rethrown. - */ - @Override public void lower(LoweringTool tool) { - if (isLowered()) { - return; - } - LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp())); - loadException.setStateAfter(stateAfter()); - List<GuardedNode> guardedNodes = new ArrayList<>(); - for (Node usage : usages().snapshot()) { - if (usage instanceof GuardedNode) { - // can't replace the guard with LoadExceptionObjectNode as it is not a GuardingNode - // so temporarily change it to remove the GuardedNode from usages - GuardedNode guardedNode = (GuardedNode) usage; - guardedNode.setGuard(graph().add(new BeginNode())); - guardedNodes.add(guardedNode); - } - } - replaceAtUsages(loadException); - for (GuardedNode guardedNode : guardedNodes) { - BeginNode dummyGuard = (BeginNode) guardedNode.getGuard(); - guardedNode.setGuard(this); - graph().removeFixed(dummyGuard); - } - graph().addAfterFixed(this, loadException); - setStateAfter(null); - setStamp(StampFactory.forVoid()); - loadException.lower(tool); + tool.getLowerer().lower(this, tool); } @Override public boolean verify() { - if (isLowered()) { - return true; - } - assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state"); + assertTrue(stateAfter() != null, "an exception handler needs a frame state"); return super.verify(); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.java; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; @@ -33,21 +34,20 @@ /** * The {@code InstanceOfNode} represents an instanceof test. */ -public final class InstanceOfNode extends LogicNode implements Canonicalizable, Lowerable, Virtualizable { +public final class InstanceOfNode extends UnaryOpLogicNode implements Canonicalizable, Lowerable, Virtualizable { - @Input private ValueNode object; private final ResolvedJavaType type; private JavaTypeProfile profile; /** * Constructs a new InstanceOfNode. - * + * * @param type the target type of the instanceof check * @param object the object being tested by the instanceof */ public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) { + super(object); this.type = type; - this.object = object; this.profile = profile; assert type != null; } @@ -59,13 +59,39 @@ @Override public Node canonical(CanonicalizerTool tool) { - Stamp stamp = object().stamp(); + switch (evaluate(object())) { + case FALSE: + return LogicConstantNode.contradiction(graph()); + case TRUE: + return LogicConstantNode.tautology(graph()); + case UNKNOWN: + Stamp stamp = object().stamp(); + if (stamp instanceof ObjectStamp) { + ObjectStamp objectStamp = (ObjectStamp) stamp; + ResolvedJavaType stampType = objectStamp.type(); + if (stampType != null && type().isAssignableFrom(stampType)) { + if (!objectStamp.nonNull()) { + // the instanceof matches if the object is non-null, so return true + // depending on the null-ness. + IsNullNode isNull = graph().unique(new IsNullNode(object())); + return graph().unique(new LogicNegationNode(isNull)); + } + } + } + return this; + } + return this; + } + + @Override + public TriState evaluate(ValueNode forObject) { + Stamp stamp = forObject.stamp(); if (!(stamp instanceof ObjectStamp)) { - return this; + return TriState.UNKNOWN; } ObjectStamp objectStamp = (ObjectStamp) stamp; if (objectStamp.alwaysNull()) { - return LogicConstantNode.contradiction(graph()); + return TriState.FALSE; } ResolvedJavaType stampType = objectStamp.type(); @@ -74,34 +100,25 @@ if (subType) { if (objectStamp.nonNull()) { // the instanceOf matches, so return true - return LogicConstantNode.tautology(graph()); - } else { - // the instanceof matches if the object is non-null, so return true depending on - // the null-ness. - IsNullNode isNull = graph().unique(new IsNullNode(object())); - return graph().unique(new LogicNegationNode(isNull)); + return TriState.TRUE; } } else { if (objectStamp.isExactType()) { // since this type check failed for an exact type we know that it can never // succeed at run time. we also don't care about null values, since they will // also make the check fail. - return LogicConstantNode.contradiction(graph()); + return TriState.FALSE; } else { boolean superType = stampType.isAssignableFrom(type()); if (!superType && !stampType.isInterface() && !type().isInterface()) { - return LogicConstantNode.contradiction(graph()); + return TriState.FALSE; } // since the subtype comparison was only performed on a declared type we don't // really know if it might be true at run time... } } } - return this; - } - - public ValueNode object() { - return object; + return TriState.UNKNOWN; } /** @@ -121,7 +138,7 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); + State state = tool.getObjectState(object()); if (state != null) { tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph())); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2009, 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.nodes.java; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -/** - * Loads an exception object passed by the runtime from a callee to an exception handler in a - * caller. The node is only produced when lowering an {@link ExceptionObjectNode}. - * <p> - * The frame state upon entry to an exception handler is such that it is a - * {@link BytecodeFrame#rethrowException rethrow exception} state and the stack contains exactly the - * exception object (per the JVM spec) to rethrow. This means that the code generated for this node - * must not cause a deoptimization as the runtime/interpreter would not have a valid location to - * find the exception object to be rethrown. - */ -public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable { - - public LoadExceptionObjectNode(Stamp stamp) { - super(stamp); - } - - @Override - public void lower(LoweringTool tool) { - tool.getLowerer().lower(this, tool); - } -}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,13 +22,14 @@ */ package com.oracle.graal.nodes.spi; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; /** * Interface implemented by nodes that can replace themselves with lower level nodes during a phase * that transforms a graph to replace higher level nodes with lower level nodes. */ -public interface Lowerable { +public interface Lowerable extends NodeInterface { /** * Expand this node into lower level nodes expressing the same semantics. If the introduced
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.spi; - -import com.oracle.graal.nodes.extended.*; - -/** - * Marks nodes which may be lowered in combination with a memory operation. - */ -public interface MemoryArithmeticLIRLowerable { - - /** - * Attempt to generate a memory form of a node operation. On platforms that support it this will - * be called when the merging is safe. - * - * @param gen - * @param access the memory input which can potentially merge into this operation. - * @return null if it's not possible to emit a memory form of this operation. A non-null value - * will be set as the operand of this node. - */ - boolean generate(MemoryArithmeticLIRLowerer gen, Access access); -}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.spi; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.calc.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; - -/** - * This interface can be used to generate LIR for arithmetic operations where one of the operations - * is load (@see ArithmeticLIRLowerable). - */ -public interface MemoryArithmeticLIRLowerer { - - Value setResult(ValueNode x, Value operand); - - Value emitAddMemory(ValueNode x, ValueNode y, Access access); - - Value emitMulMemory(ValueNode x, ValueNode y, Access access); - - Value emitSubMemory(ValueNode x, ValueNode y, Access access); - - Value emitDivMemory(ValueNode x, ValueNode y, Access access); - - Value emitRemMemory(ValueNode x, ValueNode y, Access access); - - Value emitXorMemory(ValueNode x, ValueNode y, Access access); - - Value emitOrMemory(ValueNode x, ValueNode y, Access access); - - Value emitAndMemory(ValueNode x, ValueNode y, Access access); - - Value emitReinterpretMemory(Stamp stamp, Access access); - - Value emitSignExtendMemory(Access access, int fromBits, int toBits); - - Value emitNarrowMemory(int resultBits, Access access); - - Value emitZeroExtendMemory(int inputBits, int resultBits, Access access); - - Value emitFloatConvertMemory(FloatConvert op, Access access); - - boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred); - - boolean emitIfMemory(IfNode ifNode, Access access); - -}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRBuilderTool.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,10 +26,12 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; public interface NodeLIRBuilderTool extends NodeMappableLIRBuilder { @@ -68,5 +70,13 @@ Value[] visitInvokeArguments(CallingConvention cc, Collection<ValueNode> arguments); - MemoryArithmeticLIRLowerer getMemoryLowerer(); + Variable newVariable(Kind kind); + + void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length); + + void emitBitCount(Variable result, Value operand); + + void emitBitScanForward(Variable result, Value operand); + + void doBlock(Block block, StructuredGraph graph, BlockMap<List<ScheduledNode>> blockMap); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Tue Apr 29 18:35:10 2014 +0200 @@ -29,9 +29,7 @@ /** * Interface for nodes which have {@link FrameState} nodes as input. */ -public interface NodeWithState { - - Node asNode(); +public interface NodeWithState extends NodeInterface { default NodeIterable<FrameState> states() { return asNode().inputs().filter(FrameState.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,11 +24,12 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; /** * Interface for service providers that register replacements with the compiler. */ public interface ReplacementsProvider { - void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target); + void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Tue Apr 29 18:35:10 2014 +0200 @@ -506,22 +506,22 @@ } /** - * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain ValueNode} has if it is + * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is * a {@linkplain Stamp#isLegal() legal} Object value. * * @param node the node to check - * @return the javat type this value has if it is a legal Object type, null otherwise + * @return the Java type this value has if it is a legal Object type, null otherwise */ public static ResolvedJavaType typeOrNull(ValueNode node) { return typeOrNull(node.stamp()); } /** - * Returns the {@linkplain ResolvedJavaType java type} this {@linkplain Stamp} has if it is a + * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a * {@linkplain Stamp#isLegal() legal} Object stamp. * * @param stamp the stamp to check - * @return the java type this stamp has if it is a legal Object stamp, null otherwise + * @return the Java type this stamp has if it is a legal Object stamp, null otherwise */ public static ResolvedJavaType typeOrNull(Stamp stamp) { if (stamp instanceof ObjectStamp && stamp.isLegal()) { @@ -532,12 +532,12 @@ /** * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#isLegal() legal} Object - * value whose java type is known exactly. If this method returns true then the - * {@linkplain ResolvedJavaType java type} returned by {@link #typeOrNull(ValueNode)} is the - * concrete dynamic/runtime java type of this value. + * value whose Java type is known exactly. If this method returns true then the + * {@linkplain ResolvedJavaType Java type} returned by {@link #typeOrNull(ValueNode)} is the + * concrete dynamic/runtime Java type of this value. * * @param node the node to check - * @return true if this node represents a legal object value whose java type is known exactly + * @return true if this node represents a legal object value whose Java type is known exactly */ public static boolean isExactType(ValueNode node) { return isExactType(node.stamp()); @@ -545,12 +545,12 @@ /** * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} Object - * stamp whose {@linkplain ResolvedJavaType java type} is known exactly. If this method returns - * true then the java type returned by {@link #typeOrNull(Stamp)} is the only concrete - * dynamic/runtime java type possible for values of this stamp. + * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns + * true then the Java type returned by {@link #typeOrNull(Stamp)} is the only concrete + * dynamic/runtime Java type possible for values of this stamp. * * @param stamp the stamp to check - * @return true if this node represents a legal object stamp whose java type is known exactly + * @return true if this node represents a legal object stamp whose Java type is known exactly */ public static boolean isExactType(Stamp stamp) { if (stamp instanceof ObjectStamp && stamp.isLegal()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; @@ -42,12 +43,12 @@ } }; - public static void killCFG(Node node) { + public static void killCFG(Node node, SimplifierTool tool) { assert node.isAlive(); if (node instanceof AbstractEndNode) { // We reached a control flow end. AbstractEndNode end = (AbstractEndNode) node; - killEnd(end); + killEnd(end, tool); } else { // Normal control flow node. /* @@ -57,13 +58,17 @@ * while processing one branch. */ for (Node successor : node.successors()) { - killCFG(successor); + killCFG(successor, tool); } } propagateKill(node); } - private static void killEnd(AbstractEndNode end) { + public static void killCFG(Node node) { + killCFG(node, null); + } + + private static void killEnd(AbstractEndNode end, SimplifierTool tool) { MergeNode merge = end.merge(); if (merge != null) { merge.removeEnd(end); @@ -85,12 +90,17 @@ killCFG(loopBody); } begin.safeDelete(); - } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not - // a - // loop - // anymore + } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { + // not a loop anymore + if (tool != null) { + merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage))); + } graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); - } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore + } else if (merge.phiPredecessorCount() == 1) { + // not a merge anymore + if (tool != null) { + merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage))); + } graph.reduceTrivialMerge(merge); } } @@ -333,6 +343,14 @@ return v; } + public static boolean tryKillUnused(Node node) { + if (node.isAlive() && isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) { + killWithUnusedFloatingInputs(node); + return true; + } + return false; + } + /** * Exhaustive search for {@link GraphUtil#originalValue(ValueNode)} when a simple search fails. * This can happen in the presence of complicated phi/proxy/phi constructs.
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Tue Apr 29 18:35:10 2014 +0200 @@ -40,8 +40,10 @@ * * <pre> * ServiceLoader<Options> sl = ServiceLoader.loadInstalled(Options.class); - * for (OptionDescriptor desc : sl) { - * // use desc + * for (Options opts : sl) { + * for (OptionDescriptor desc : sl) { + * // use desc + * } * } * </pre> */
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -178,7 +178,7 @@ } StructuredGraph graph = (StructuredGraph) node.graph(); Mark mark = graph.getMark(); - if (!tryKillUnused(node)) { + if (!GraphUtil.tryKillUnused(node)) { if (!tryCanonicalize(node, nodeClass)) { if (node instanceof ValueNode) { ValueNode valueNode = (ValueNode) node; @@ -200,14 +200,6 @@ } } - private static boolean tryKillUnused(Node node) { - if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(node); - return true; - } - return false; - } - public static boolean tryGlobalValueNumbering(Node node, NodeClass nodeClass) { if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) { Node newNode = node.graph().findDuplicate(node); @@ -354,7 +346,7 @@ @Override public void deleteBranch(Node branch) { branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch); + GraphUtil.killCFG(branch, this); } /** @@ -383,7 +375,7 @@ @Override public void removeIfUnused(Node node) { - tryKillUnused(node); + GraphUtil.tryKillUnused(node); } @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Apr 29 18:35:10 2014 +0200 @@ -1316,8 +1316,6 @@ assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal(); assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase"; - Kind returnKind = invokeNode.getKind(); - FrameState stateAfter = invoke.stateAfter(); assert stateAfter == null || stateAfter.isAlive(); if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) { @@ -1401,38 +1399,8 @@ } if (stateAfter != null) { - FrameState outerFrameState = null; + processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge); int callerLockDepth = stateAfter.nestedLockDepth(); - for (FrameState original : inlineGraph.getNodes(FrameState.class)) { - FrameState frameState = (FrameState) duplicates.get(original); - if (frameState != null && frameState.isAlive()) { - assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; - if (frameState.bci == BytecodeFrame.AFTER_BCI) { - frameState.replaceAndDelete(returnKind == Kind.Void ? stateAfter : stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), returnKind, - frameState.stackAt(0))); - } else if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized())) { - if (stateAtExceptionEdge != null) { - frameState.replaceAndDelete(stateAtExceptionEdge); - } else { - handleMissingAfterExceptionFrameState(frameState); - } - } else if (frameState.bci == BytecodeFrame.UNWIND_BCI) { - handleMissingAfterExceptionFrameState(frameState); - } else { - // only handle the outermost frame states - if (frameState.outerFrameState() == null) { - assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()); - assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && - frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci; - if (outerFrameState == null) { - outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.getKind()); - outerFrameState.setDuringCall(true); - } - frameState.setOuterFrameState(outerFrameState); - } - } - } - } if (callerLockDepth != 0) { for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) { MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original); @@ -1470,10 +1438,61 @@ return duplicates; } - protected static void handleMissingAfterExceptionFrameState(FrameState nonReplacableFrameState) { - Graph graph = nonReplacableFrameState.graph(); + protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates, FrameState stateAtExceptionEdge) { + FrameState stateAtReturn = invoke.stateAfter(); + FrameState outerFrameState = null; + Kind invokeReturnKind = invoke.asNode().getKind(); + for (FrameState original : inlineGraph.getNodes(FrameState.class)) { + FrameState frameState = (FrameState) duplicates.get(original); + if (frameState != null && frameState.isAlive()) { + if (frameState.bci == BytecodeFrame.AFTER_BCI) { + /* + * pop return kind from invoke's stateAfter and replace with this frameState's + * return value (top of stack) + */ + FrameState stateAfterReturn = stateAtReturn; + if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) { + stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0)); + } + frameState.replaceAndDelete(stateAfterReturn); + } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) { + /* + * pop exception object from invoke's stateAfter and replace with this + * frameState's exception object (top of stack) + */ + FrameState stateAfterException = stateAtExceptionEdge; + if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) { + stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0)); + } + frameState.replaceAndDelete(stateAfterException); + } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + handleMissingAfterExceptionFrameState(frameState); + } else { + // only handle the outermost frame states + if (frameState.outerFrameState() == null) { + assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; + assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()); + assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && + frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci; + if (outerFrameState == null) { + outerFrameState = stateAtReturn.duplicateModified(invoke.bci(), stateAtReturn.rethrowException(), invokeReturnKind); + outerFrameState.setDuringCall(true); + } + frameState.setOuterFrameState(outerFrameState); + } + } + } + } + } + + private static boolean isStateAfterException(FrameState frameState) { + return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized()); + } + + protected static void handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) { + Graph graph = nonReplaceableFrameState.graph(); NodeWorkList workList = graph.createNodeWorkList(); - workList.add(nonReplacableFrameState); + workList.add(nonReplaceableFrameState); for (Node node : workList) { FrameState fs = (FrameState) node; for (Node usage : fs.usages().snapshot()) { @@ -1494,7 +1513,10 @@ GraphUtil.killCFG(end); } } else { - DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + if (fixedStateSplit instanceof BeginNode) { + deoptimizeNode = BeginNode.begin(deoptimizeNode); + } fixedStateSplit.replaceAtPredecessor(deoptimizeNode); GraphUtil.killCFG(fixedStateSplit); }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -62,7 +62,7 @@ canonicalizer.applyIncremental(graph, context, listener.getChangedNodes()); listener.getChangedNodes().clear(); if (++count > MAX_ITERATIONS) { - throw new BailoutException("Number of iterations in conditional elimination phase exceeds " + MAX_ITERATIONS); + throw new BailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds " + MAX_ITERATIONS); } } }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -240,14 +240,20 @@ private final PhaseContext context; private final SchedulePhase schedule; + private final int iteration; private Round(int iteration, PhaseContext context) { - super("LoweringIteration" + iteration); + this.iteration = iteration; this.context = context; this.schedule = new SchedulePhase(); } @Override + protected CharSequence createName() { + return "LoweringIteration" + iteration; + } + + @Override public void run(StructuredGraph graph) { schedule.apply(graph, false); processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -55,8 +55,11 @@ private static final String GROUP_NAME = "~profiled weight"; private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)"; + private static final String GROUP_NAME_INVOKES = "~profiled invokes"; private static final boolean WITH_SECTION_HEADER = false; + private static boolean WITH_INVOKE_FREE_SECTIONS = false; + private static boolean WITH_INVOKES = true; @Override protected void run(StructuredGraph graph) { @@ -72,7 +75,22 @@ addSectionCounters(loop.header.getBeginNode(), loop.blocks, loop.children, schedule, probabilities); } } - addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities); + // don't put the counter increase directly after the start (problems with OSR) + FixedWithNextNode current = graph.start(); + while (current.next() instanceof FixedWithNextNode) { + current = (FixedWithNextNode) current.next(); + } + addSectionCounters(current, Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities); + + if (WITH_INVOKES) { + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + DynamicCounterNode.addCounterBefore(GROUP_NAME_INVOKES, invoke.callTarget().targetName(), 1, true, invoke.asNode()); + + } + } + } } private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) { @@ -82,7 +100,7 @@ } double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start); DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next()); - if (!hasInvoke(blocks)) { + if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) { DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next()); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,233 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.code.Assumptions; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugMetric; +import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.spi.CanonicalizerTool; +import com.oracle.graal.nodes.*; +import com.oracle.graal.compiler.common.type.ObjectStamp; +import com.oracle.graal.phases.graph.PostOrderNodeIterator; +import com.oracle.graal.phases.tiers.PhaseContext; + +import java.util.ArrayList; + +/** + * <p> + * For readability purposes the code realizing control-flow-sensitive reductions is chopped into + * several classes in an inheritance hierarchy, this class being their common ancestor. That way, + * many dependencies can be ruled out immediately (e.g., private members of a class aren't needed by + * other classes). The whole thing is reminiscent of trait-based patterns, minus their + * disadvantages. + * </p> + * + * + * <p> + * This class makes available little more than a few fields and a few utility methods used + * throughout the remaining components making up control-flow sensitive reductions. + * </p> + */ +public abstract class BaseReduction extends PostOrderNodeIterator<State> { + + protected static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved"); + protected static final DebugMetric metricGuardingPiNodeRemoved = Debug.metric("GuardingPiNodeRemoved"); + protected static final DebugMetric metricFixedGuardNodeRemoved = Debug.metric("FixedGuardNodeRemoved"); + protected static final DebugMetric metricMethodResolved = Debug.metric("MethodResolved"); + + /** + * <p> + * Upon visiting a {@link com.oracle.graal.nodes.FixedNode FixedNode} in + * {@link #node(com.oracle.graal.nodes.FixedNode)}, an impossible path may be detected. We'd + * like to insert an unconditional deoptimizing node as a hint for Dead Code Elimination to kill + * that branch. However that can't be made on the go (a + * {@link com.oracle.graal.nodes.ControlSinkNode} can't have successors). Thus their insertion + * is postponed till the end of a round of + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}. + * </p> + * + * @see State#impossiblePath() + * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#finished() + */ + public static class PostponedDeopt { + + private final boolean goesBeforeFixed; + private final FixedWithNextNode fixed; + private final DeoptimizationReason deoptReason; + + public PostponedDeopt(boolean goesBeforeFixed, FixedWithNextNode fixed, DeoptimizationReason deoptReason) { + this.goesBeforeFixed = goesBeforeFixed; + this.fixed = fixed; + this.deoptReason = deoptReason; + } + + public void doRewrite(LogicNode falseConstant) { + StructuredGraph graph = fixed.graph(); + // have to insert a FixedNode other than a ControlSinkNode + FixedGuardNode buckStopsHere = graph.add(new FixedGuardNode(falseConstant, deoptReason, DeoptimizationAction.None)); + if (goesBeforeFixed) { + fixed.replaceAtPredecessor(buckStopsHere); + } else { + graph.addAfterFixed(fixed, buckStopsHere); + } + } + + } + + protected static class PostponedDeopts extends ArrayList<PostponedDeopt> { + + private static final long serialVersionUID = 7188324432387121238L; + + /** + * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right before the fixed + * argument, will be done once we're done traversing the graph. + * + * @see #finished() + */ + void addDeoptBefore(FixedWithNextNode fixed, DeoptimizationReason deoptReason) { + add(new PostponedDeopt(true, fixed, deoptReason)); + } + + /** + * Enqueue adding a {@link com.oracle.graal.nodes.DeoptimizeNode} right after the fixed + * argument, will be done once we're done traversing the graph. + * + * @see #finished() + */ + void addDeoptAfter(FixedWithNextNode fixed, DeoptimizationReason deoptReason) { + add(new PostponedDeopt(false, fixed, deoptReason)); + } + + } + + /** + * <p> + * One of the promises of + * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)} + * is that a "maximally reduced" node is returned. That is achieved in part by leveraging + * {@link com.oracle.graal.graph.Node#canonical(com.oracle.graal.graph.spi.CanonicalizerTool)}. + * Doing so, in turn, requires this subclass of + * {@link com.oracle.graal.graph.spi.CanonicalizerTool}. + * </p> + */ + public final class Tool implements CanonicalizerTool { + + private final PhaseContext context; + + public Tool(PhaseContext context) { + this.context = context; + } + + @Override + public Assumptions assumptions() { + return context.getAssumptions(); + } + + @Override + public MetaAccessProvider getMetaAccess() { + return context.getMetaAccess(); + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return context.getConstantReflection(); + } + + /** + * Postpone + * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} + * until {@link FlowSensitiveReduction#finished()} for the reasons covered there. + */ + @Override + public void removeIfUnused(Node node) { + // GraphUtil.tryKillUnused(node); + } + + @Override + public boolean canonicalizeReads() { + return false; + } + } // end of class FlowSensitiveReduction.Tool + + protected final LogicConstantNode trueConstant; + protected final LogicConstantNode falseConstant; + protected final ConstantNode nullConstant; + + protected final CanonicalizerTool tool; + protected final StructuredGraph graph; + + protected EquationalReasoner reasoner; + + protected final PostponedDeopts postponedDeopts = new PostponedDeopts(); + + protected BaseReduction(FixedNode start, State initialState, PhaseContext context) { + super(start, initialState); + graph = start.graph(); + trueConstant = LogicConstantNode.tautology(graph); + falseConstant = LogicConstantNode.contradiction(graph); + nullConstant = ConstantNode.defaultForKind(Kind.Object, graph); // ConstantNode.forObject(null, + // metaAccess, graph); + tool = new Tool(context); + reasoner = new EquationalReasoner(graph, tool, trueConstant, falseConstant, nullConstant); + } + + /** + * <p> + * Test whether the output's stamp is an upcast of that of the input. For example, upon + * replacing a CheckCastNode in + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, com.oracle.graal.nodes.ValueNode)} + * we don't want to be left with an upcast, as it loses precision. + * </p> + * + * <p> + * As usual with object stamps, they can be compared along different dimensions (alwaysNull, + * etc.) It's enough for one such dimension to show precision loss for the end result to be + * reported as such. + * </p> + * + */ + protected static boolean precisionLoss(ValueNode input, ValueNode output) { + ObjectStamp inputStamp = (ObjectStamp) input.stamp(); + ObjectStamp outputStamp = (ObjectStamp) output.stamp(); + if (FlowUtil.isMorePrecise(inputStamp.type(), outputStamp.type())) { + return true; + } + if (lessThan(outputStamp.alwaysNull(), inputStamp.alwaysNull())) { + return true; + } + if (lessThan(outputStamp.nonNull(), inputStamp.nonNull())) { + return true; + } + if (lessThan(outputStamp.isExactType(), inputStamp.isExactType())) { + return true; + } + return false; + } + + private static boolean lessThan(boolean a, boolean b) { + return a == false && b == true; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CastCheckExtractor.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,87 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.ResolvedJavaType; +import com.oracle.graal.nodes.LogicNode; +import com.oracle.graal.nodes.ShortCircuitOrNode; +import com.oracle.graal.nodes.ValueNode; +import com.oracle.graal.nodes.calc.IsNullNode; +import com.oracle.graal.nodes.java.InstanceOfNode; + +/** + * @see #extract(com.oracle.graal.nodes.LogicNode) + */ +class CastCheckExtractor { + + public final ResolvedJavaType type; + public final ValueNode subject; + + CastCheckExtractor(ResolvedJavaType type, ValueNode subject) { + this.type = type; + this.subject = subject; + } + + private static CastCheckExtractor extractCastCheckInfo(LogicNode x, LogicNode y) { + if (x instanceof IsNullNode) { + IsNullNode isNull = (IsNullNode) x; + ValueNode subject = isNull.object(); + if (isInstanceOfCheckOn(y, subject)) { + InstanceOfNode iOf = (InstanceOfNode) y; + return new CastCheckExtractor(iOf.type(), subject); + } + } + return null; + } + + /** + * This method detects whether the argument realizes the CheckCast pattern. If so, distills and + * returns the essentials of such check, otherwise returns null. + */ + static CastCheckExtractor extract(LogicNode cond) { + if (!(cond instanceof ShortCircuitOrNode)) { + return null; + } + ShortCircuitOrNode orNode = (ShortCircuitOrNode) cond; + if (orNode.isXNegated() || orNode.isYNegated()) { + return null; + } + CastCheckExtractor result = extractCastCheckInfo(orNode.getX(), orNode.getY()); + if (result != null) { + return result; + } + result = extractCastCheckInfo(orNode.getY(), orNode.getX()); + return result; + } + + /** + * Porcelain method. + */ + static boolean isInstanceOfCheckOn(LogicNode cond, ValueNode subject) { + if (!(cond instanceof InstanceOfNode)) { + return false; + } + InstanceOfNode io = (InstanceOfNode) cond; + return io.object() == subject; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,337 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.IsNullNode; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.compiler.common.type.ObjectStamp; +import com.oracle.graal.compiler.common.type.StampFactory; +import com.oracle.graal.nodes.type.StampTool; +import com.oracle.graal.phases.tiers.PhaseContext; + +import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY; + +/** + * <p> + * This class implements control-flow sensitive reductions for + * {@link com.oracle.graal.nodes.java.CheckCastNode}. + * </p> + * + * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode) + */ +public abstract class CheckCastReduction extends GuardingPiReduction { + + public CheckCastReduction(FixedNode start, State initialState, PhaseContext context) { + super(start, initialState, context); + } + + /** + * <p> + * This phase is able to refine the types of reference-values at use sites provided a + * {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} is available witnessing + * that fact. + * </p> + * + * <p> + * This method turns non-redundant {@link com.oracle.graal.nodes.java.CheckCastNode}s into + * {@link com.oracle.graal.nodes.GuardingPiNode}s. Once such lowering has been performed (during + * run N of this phase) follow-up runs attempt to further simplify the resulting node, see + * {@link EquationalReasoner#downcastGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode, Witness)} + * and {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)} + * </p> + * + * <p> + * Precondition: the inputs (ie, object) hasn't been deverbosified yet. + * </p> + */ + protected final void visitCheckCastNode(CheckCastNode checkCast) { + + /* + * checkCast.object() hasn't been deverbosified yet. + */ + + if (!FlowUtil.hasLegalObjectStamp(checkCast)) { + // This situation is exercised by test Class_cast01 + return; + } + + final ValueNode subject = checkCast.object(); + final ResolvedJavaType toType = checkCast.type(); + ObjectStamp subjectStamp = (ObjectStamp) subject.stamp(); + ResolvedJavaType subjectType = subjectStamp.type(); + + // --------- checkCast deemed redundant by subject-stamp alone --------- + // --------- in particular due to stamp informing always null ---------- + boolean isRedundantPerStamp = StampTool.isObjectAlwaysNull(subject) || (subjectType != null && toType.isAssignableFrom(subjectType)); + if (isRedundantPerStamp) { + metricCheckCastRemoved.increment(); + checkCast.replaceAtUsages(subject); + graph.removeFixed(checkCast); + return; + } + + assert !StampTool.isObjectAlwaysNull(subject) : "Null as per stamp subjects should have been handled above"; + + // --------- checkCast deemed unsatisfiable by subject-stamp alone --------- + if (state.knownNotToConform(subject, toType)) { + postponedDeopts.addDeoptBefore(checkCast, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException); + state.impossiblePath(); + // let FixedGuardNode(false).simplify() prune the dead-code control-path + return; + } + + /* + * Remark: subject may be TypeProxyNode, GuardedValueNode, ProxyNode, GuardingPiNode, among + * others. + */ + + PiNode untrivialNull = reasoner.nonTrivialNull(subject); + if (untrivialNull != null) { + metricCheckCastRemoved.increment(); + checkCast.replaceAtUsages(untrivialNull); + graph.removeFixed(checkCast); + return; + } + + Witness w = state.typeInfo(subject); + + if (w == null) { + /* + * If there's no witness, attempting `downcast(subject)` is futile. + */ + visitCheckCastNodeLackingWitness(checkCast); + return; + } + + visitCheckCastNodeWithWitness(checkCast); + + } + + /** + * Given that no witness is available for the {@link com.oracle.graal.nodes.java.CheckCastNode} + * 's subject there's no point in downcasting such subject, ie no + * {@link com.oracle.graal.nodes.PiNode} can be fabricated for the subject. + * + * @see #lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, + * com.oracle.graal.nodes.ValueNode) + * + */ + private void visitCheckCastNodeLackingWitness(CheckCastNode checkCast) { + final ValueNode subject = checkCast.object(); + final ResolvedJavaType toType = checkCast.type(); + if (toType.isInterface()) { + return; + } + assert reasoner.downcast(subject) == subject; + lowerCheckCastAnchorFriendlyWay(checkCast, subject); + } + + /** + * Porcelain method. + * + * <p> + * Rather than tracking the CheckCastNode via {@link com.oracle.graal.phases.common.cfs.State + * State} (doing so woud add a special case because a + * {@link com.oracle.graal.nodes.java.CheckCastNode} isn't a + * {@link com.oracle.graal.nodes.extended.GuardingNode}) this method creates an anchor by + * lowering the CheckCastNode into a FixedGuardNode. Not the same way as done by + * {@link com.oracle.graal.nodes.java.CheckCastNode#lower(com.oracle.graal.nodes.spi.LoweringTool)} + * which lowers into a {@link com.oracle.graal.nodes.GuardingPiNode} (which is not a + * {@link com.oracle.graal.nodes.extended.GuardingNode}). + * </p> + * + * <p> + * With that, state tracking can proceed as usual. + * </p> + * + * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode) + * + */ + public void lowerCheckCastAnchorFriendlyWay(CheckCastNode checkCast, ValueNode subject) { + ValueNode originalCheckCastObject = checkCast.object(); + + ObjectStamp subjectStamp = (ObjectStamp) subject.stamp(); + final ResolvedJavaType toType = checkCast.type(); + ObjectStamp resultStamp = (ObjectStamp) StampFactory.declared(toType); + JavaTypeProfile profile = checkCast.profile(); + + assert FlowUtil.isLegalObjectStamp(subjectStamp); + assert subjectStamp.type() == null || !toType.isAssignableFrom(subjectStamp.type()) : "No need to lower in an anchor-friendly way in the first place"; + + /* + * Depending on what is known about the subject: + * + * (a) definitely-non-null + * + * (b) null-not-seen-in-profiling + * + * (c) runtime-null-check-needed + * + * the condition (of the cast-guard to be emitted) and the stamp (of the PiNode to be + * emitted) are going to be different. Each of the three branches below deals with one of + * the cases above. + */ + LogicNode condition; + if (subjectStamp.nonNull()) { + /* + * (1 of 3) definitely-non-null + */ + // addWithoutUnique for the same reason as in CheckCastNode.lower() + condition = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile)); + reasoner.added.add(condition); + resultStamp = FlowUtil.asNonNullStamp(resultStamp); + // TODO fix in CheckCastNode.lower() + } else { + if (profile != null && profile.getNullSeen() == ProfilingInfo.TriState.FALSE) { + /* + * (2 of 3) null-not-seen-in-profiling + */ + IsNullNode isNN = graph.unique(new IsNullNode(subject)); + reasoner.added.add(isNN); + FixedGuardNode nullCheck = graph.add(new FixedGuardNode(isNN, UnreachedCode, InvalidateReprofile, true)); + graph.addBeforeFixed(checkCast, nullCheck); + // not calling wrapInPiNode() because we don't want to rememberSubstitution() + PiNode nonNullGuarded = graph.unique(new PiNode(subject, FlowUtil.asNonNullStamp(subjectStamp), nullCheck)); + reasoner.added.add(nonNullGuarded); + // addWithoutUnique for the same reason as in CheckCastNode.lower() + condition = graph.addWithoutUnique(new InstanceOfNode(toType, nonNullGuarded, profile)); + reasoner.added.add(condition); + resultStamp = FlowUtil.asNonNullStamp(resultStamp); + } else { + /* + * (3 of 3) runtime-null-check-needed + */ + // addWithoutUnique for the same reason as in CheckCastNode.lower() + InstanceOfNode typeTest = graph.addWithoutUnique(new InstanceOfNode(toType, subject, profile)); + reasoner.added.add(typeTest); + LogicNode nullTest = graph.unique(new IsNullNode(subject)); + reasoner.added.add(nullTest); + // TODO (ds) replace with probability of null-seen when available + final double shortCircuitProbability = NOT_FREQUENT_PROBABILITY; + condition = LogicNode.or(nullTest, typeTest, shortCircuitProbability); + reasoner.added.add(condition); + } + } + + /* + * Add a cast-guard (checking only what needs to be checked) and a PiNode (to be used in + * place of the CheckCastNode). + */ + FixedGuardNode castGuard = graph.add(new FixedGuardNode(condition, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException, InvalidateReprofile)); + graph.addBeforeFixed(checkCast, castGuard); + + assert FlowUtil.isLegalObjectStamp(resultStamp); + Witness w = state.typeInfo(subject); + assert !isTypeOfWitnessBetter(w, resultStamp); + + if (!FlowUtil.lacksUsages(checkCast)) { + // not calling wrapInPiNode() because we don't want to rememberSubstitution() + PiNode checkedObject = graph.unique(new PiNode(subject, resultStamp, castGuard)); + reasoner.added.add(checkedObject); + assert !precisionLoss(originalCheckCastObject, checkedObject); + assert !precisionLoss(subject, checkedObject); + checkCast.replaceAtUsages(checkedObject); + } + + graph.removeFixed(checkCast); + + if (resultStamp.nonNull()) { + state.trackIO(subject, toType, castGuard); + } else { + state.trackCC(subject, toType, castGuard); + } + } + + /** + * Porcelain method. + */ + public static boolean isTypeOfWitnessBetter(Witness w, ObjectStamp stamp) { + if (w == null) { + return false; + } + return FlowUtil.isMorePrecise(w.type(), stamp.type()); + } + + /** + * + * Please note in this method "subject" refers to the downcasted input to the checkCast. + * + * @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode) + */ + private void visitCheckCastNodeWithWitness(CheckCastNode checkCast) { + + final ResolvedJavaType toType = checkCast.type(); + + ValueNode subject; + if (checkCast.object() instanceof CheckCastNode) { + subject = reasoner.downcast(checkCast); + if (subject == checkCast) { + subject = reasoner.downcast(checkCast.object()); + } + } else { + subject = reasoner.downcast(checkCast.object()); + } + + ObjectStamp subjectStamp = (ObjectStamp) subject.stamp(); + ResolvedJavaType subjectType = subjectStamp.type(); + + // TODO move this check to downcast() + assert !precisionLoss(checkCast.object(), subject); + + /* + * At this point, two sources of (partial) information: the witness and the stamp of + * subject. The latter might be more precise than the witness (eg, subject might be + * GuardedValueNode) + */ + + // --------- checkCast made redundant by downcasting its input --------- + if (subjectType != null && toType.isAssignableFrom(subjectType)) { + checkCast.replaceAtUsages(subject); + graph.removeFixed(checkCast); + return; + } + + /* + * At this point, `downcast()` might or might not have delivered a more precise value. If + * more precise, it wasn't precise enough to conform to `toType`. Even so, for the + * `toType.isInterface()` case (dealt with below) we'll replace the checkCast's input with + * that value (its class-stamp being more precise than the original). + */ + + if (toType.isInterface()) { + boolean wasDowncasted = (subject != checkCast.object()); + if (wasDowncasted) { + FlowUtil.replaceInPlace(checkCast, checkCast.object(), subject); + } + return; + } + + lowerCheckCastAnchorFriendlyWay(checkCast, subject); + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,946 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.ResolvedJavaType; +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugMetric; +import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.NodeBitMap; +import com.oracle.graal.graph.spi.CanonicalizerTool; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.FloatingNode; +import com.oracle.graal.nodes.calc.IsNullNode; +import com.oracle.graal.nodes.calc.ObjectEqualsNode; +import com.oracle.graal.nodes.extended.GuardedNode; +import com.oracle.graal.nodes.extended.GuardingNode; +import com.oracle.graal.nodes.java.CheckCastNode; +import com.oracle.graal.nodes.java.InstanceOfNode; +import com.oracle.graal.nodes.spi.ValueProxy; +import com.oracle.graal.compiler.common.type.IllegalStamp; +import com.oracle.graal.compiler.common.type.ObjectStamp; +import com.oracle.graal.compiler.common.type.StampFactory; +import com.oracle.graal.nodes.type.StampTool; +import com.oracle.graal.nodes.util.GraphUtil; + +import java.util.IdentityHashMap; +import java.util.Set; + +/** + * <p> + * This class implements a simple partial evaluator that recursively reduces a given + * {@link com.oracle.graal.nodes.calc.FloatingNode} into a simpler one based on the current state. + * Such evaluator comes handy when visiting a {@link com.oracle.graal.nodes.FixedNode} N, just + * before updating the state for N. At the pre-state, an {@link EquationalReasoner} can be used to + * reduce N's inputs (actually only those inputs of Value and Condition + * {@link com.oracle.graal.graph.InputType InputType}). For an explanation of where it's warranted + * to replace "old input" with "reduced input", see the inline comments in method + * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node n) deverbosify(Node n)} + * </p> + * + * <p> + * The name {@link EquationalReasoner EquationalReasoner} was chosen because it conveys what it + * does. + * </p> + */ +public final class EquationalReasoner { + + private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved"); + private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved"); + private static final DebugMetric metricObjectEqualsRemoved = Debug.metric("ObjectEqualsRemoved"); + private static final DebugMetric metricEquationalReasoning = Debug.metric("EquationalReasoning"); + private static final DebugMetric metricDowncasting = Debug.metric("Downcasting"); + + private final StructuredGraph graph; + private final CanonicalizerTool tool; + private final LogicConstantNode trueConstant; + private final LogicConstantNode falseConstant; + private final ConstantNode nullConstant; + + private State state; + private NodeBitMap visited; + + /** + * The reduction of a {@link com.oracle.graal.nodes.calc.FloatingNode} performed by + * {@link EquationalReasoner EquationalReasoner} may result in a FloatingNode being added to the + * graph. Those nodes aren't tracked in the {@link EquationalReasoner#visited visited} + * {@link com.oracle.graal.graph.NodeBitMap NodeBitMap} but in this set instead (those nodes are + * added after the {@link com.oracle.graal.graph.NodeBitMap} was obtained). + */ + final Set<ValueNode> added = java.util.Collections.newSetFromMap(new IdentityHashMap<ValueNode, Boolean>()); + + /** + * The reduction of a FloatingNode performed by {@link EquationalReasoner EquationalReasoner} + * may result in a FloatingNode being added to the graph. Those nodes are tracked in this map, + * to avoid recomputing them. + * + * The substitutions tracked in this field become invalid as described in + * {@link #updateState(com.oracle.graal.phases.common.cfs.State) updateState(State)} + */ + private final IdentityHashMap<ValueNode, ValueNode> substs = new IdentityHashMap<>(); + + public EquationalReasoner(StructuredGraph graph, CanonicalizerTool tool, LogicConstantNode trueConstant, LogicConstantNode falseConstant, ConstantNode nullConstant) { + this.graph = graph; + this.tool = tool; + this.trueConstant = trueConstant; + this.falseConstant = falseConstant; + this.nullConstant = nullConstant; + } + + /** + * {@link #added} grows during a run of + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase + * FlowSensitiveReductionPhase}, and doesn't survive across runs. + */ + public void forceState(State s) { + state = s; + substs.clear(); + added.clear(); + visited = null; + versionNrAsofLastForce = s.versionNr; + } + + /** + * <p> + * Gaining more precise type information about an SSA value doesn't "invalidate" as such any of + * the substitutions tracked in {@link EquationalReasoner#substs substs}, at least not in the + * sense of making the value tracked by one such entry "wrong". However, clearing the + * {@link EquationalReasoner#substs substs} is still justified because next time they are + * computed, the newly computed reduction could (in principle) be more effective (due to the + * more precise type information). + * </p> + * + * <p> + * Between clearings of cached substitutions, it is expected they get applied a number of times + * to justify the bookkeeping cost. + * </p> + * + */ + public void updateState(State s) { + assert s != null; + if (state == null || state != s || state.versionNr != versionNrAsofLastForce) { + forceState(s); + } + } + + private int versionNrAsofLastForce = 0; + + /** + * Reduce the argument based on the state at the program point where the argument is consumed. + * For most FixedNodes, that's how their inputs can be reduced. Two exceptions: + * <ul> + * <li> + * the condition of a {@link com.oracle.graal.nodes.GuardingPiNode}, see + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)} + * </li> + * <li> + * the condition of a {@link com.oracle.graal.nodes.FixedGuardNode}, see + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)} + * </li> + * + * </ul> + * + * + * <p> + * Part of the reduction work is delegated to baseCase-style reducers, whose contract explicitly + * requires them not to deverbosify the argument's inputs --- the decision is made based on the + * argument only (thus "base case"). Returning the unmodified argument is how a baseCase-style + * tells this method to fall to the default case (for a floating node only: walk into the + * argument's inputs, canonicalize followed by + * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode) + * rememberSubstitution()} if any input changed). + * </p> + * + * <p> + * This method must behave as a function (idempotent query method), ie refrain from mutating the + * state other than updating caches: + * <ul> + * <li>{@link EquationalReasoner#added EquationalReasoner#added},</li> + * <li>{@link EquationalReasoner#visited EquationalReasoner#visited} and</li> + * <li>the cache updated via + * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode) + * EquationalReasoner#rememberSubstitution(ValueNode, FloatingNode)}.</li> + * </ul> + * </p> + * + * <p> + * In turn, baseCase-style reducers are even more constrained: besides behaving as functions, + * their contract prevents them from updating any caches (basically because they already grab + * the answer from caches, if the answer isn't there they should just return their unmodified + * argument). + * </p> + * + * <p> + * This method returns: + * <ul> + * <li> + * the original argument, in case no reduction possible.</li> + * <li> + * a {@link com.oracle.graal.nodes.ValueNode ValueNode} different from the argument, in case the + * conditions for a reduction were met. The node being returned might be already in the graph. + * In any case it's canonicalized already, the caller need not perform that again.</li> + * <li> + * the unmodified argument, in case no reduction was made. Otherwise, a maximally reduced + * {@link com.oracle.graal.nodes.ValueNode}.</li> + * </ul> + * </p> + * + * @see com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode) + * + * @see com.oracle.graal.phases.common.cfs.BaseReduction.Tool + * + */ + public Node deverbosify(final Node n) { + + // -------------------------------------------------------------------- + // cases that don't initiate any call-chain that may enter this method + // -------------------------------------------------------------------- + + if (n == null) { + return null; + } + assert !(n instanceof GuardNode) : "This phase not yet ready to run during MidTier"; + if (!(n instanceof ValueNode)) { + return n; + } + ValueNode v = (ValueNode) n; + if (v.stamp() instanceof IllegalStamp) { + return v; + } + if (FlowUtil.isLiteralNode(v)) { + return v; + } + ValueNode result = substs.get(v); + if (result != null) { + // picked cached substitution + return result; + } + if ((visited != null && visited.contains(n)) || added.contains(v)) { + return v; + } + + // -------------------------------------------------------------------- + // stack overflow prevention via added, visited + // -------------------------------------------------------------------- + + if (visited == null) { + visited = graph.createNodeBitMap(); + } + visited.mark(n); + + /* + * Past this point, if we ever want `n` to be deverbosified, it must be looked-up by one of + * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)` + */ + if (v instanceof ValueProxy) { + return downcast(v); + } + + if (n instanceof FloatingNode) { + /* + * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not + * possible anymore it resorts to calling `downcast()`. Thus it's ok to take the + * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be + * missed. + */ + return deverbosifyFloatingNode((FloatingNode) n); + } + + if (FlowUtil.hasLegalObjectStamp(v)) { + return downcast(v); + } + + return n; + } + + /** + * This method: + * + * <ul> + * <li> + * Recurses only over floating inputs to attempt reductions, leave anything else as is.</li> + * <li> + * Performs copy-on-write aka lazy-DAG-copying as described in source comments, in-line.</li> + * <li> + * Usage: must be called only from {@link #deverbosify(com.oracle.graal.graph.Node) + * deverbosify(Node)}.</li> + * </ul> + */ + public Node deverbosifyFloatingNode(final FloatingNode n) { + + assert n != null : "Should have been caught in deverbosify()"; + assert !(n instanceof ValueProxy) : "Should have been caught in deverbosify()"; + assert !FlowUtil.isLiteralNode(n) : "Should have been caught in deverbosify()"; + + if (n instanceof PhiNode) { + /* + * Each input to a PhiNode should be deverbosified with the state applicable to the path + * providing such input, as done in visitAbstractEndNode() + */ + return n; + } + + final FloatingNode f = baseCaseFloating(n); + if (f != n) { + return f; + } + + FloatingNode changed = null; + for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(f)) { + /* + * Although deverbosify() is invoked below, it's only for floating inputs. That way, the + * state can't be used to make invalid conclusions. + */ + Node j = (i instanceof FloatingNode) ? deverbosify(i) : i; + if (i != j) { + assert j != f; + if (changed == null) { + changed = (FloatingNode) f.copyWithInputs(); + added.add(changed); + // copyWithInputs() implies graph.unique(changed) + assert changed.isAlive(); + assert FlowUtil.lacksUsages(changed); + } + /* + * Note: we don't trade i for j at each usage of i (doing so would change meaning) + * but only at those usages consumed by `changed`. In turn, `changed` won't replace + * `n` at arbitrary usages, but only where such substitution is valid as per the + * state holding there. In practice, this means the buck stops at the "root" + * FixedNode on whose inputs deverbosify() is invoked for the first time, via + * deverbosifyInputsInPlace(). + */ + FlowUtil.replaceInPlace(changed, i, j); + } + } + if (changed == null) { + assert visited.contains(f) || added.contains(f); + if (FlowUtil.hasLegalObjectStamp(f)) { + /* + * No input has changed doesn't imply there's no witness to refine the + * floating-object value. + */ + ValueNode d = downcast(f); + return d; + } else { + return f; + } + } + FlowUtil.inferStampAndCheck(changed); + added.add(changed); + ValueNode canon = (ValueNode) changed.canonical(tool); + // might be already in `added`, no problem adding it again. + added.add(canon); + rememberSubstitution(f, canon); + return canon; + } + + /** + * In case of doubt (on whether a reduction actually triggered) it's always ok to invoke " + * <code>rememberSubstitution(f, downcast(f))</code>": this method records a map entry only if + * pre-image and image differ. + * + * @return the image of the substitution (ie, the second argument) unmodified. + */ + private <M extends ValueNode> M rememberSubstitution(ValueNode from, M to) { + assert from != null && to != null; + if (from == to) { + return to; + } + // we don't track literals because they map to themselves + if (FlowUtil.isLiteralNode(from)) { + assert from == to; + return to; + } + /* + * It's ok for different keys (which were not unique in the graph after all) to map to the + * same value. However any given key can't map to different values. + */ + ValueNode image = substs.get(from); + if (image != null) { + assert image == to; + return to; + } + substs.put(from, to); + return to; + } + + /** + * The contract for this baseCase-style method is covered in + * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node) + * EquationalReasoner#deverbosify()} + * + * @return a {@link com.oracle.graal.nodes.calc.FloatingNode} different from the argument, in + * case a reduction was made. The node being returned might be already in the graph. In + * any case it's canonicalized already, the caller need not perform that again. In case + * no reduction was made, this method returns the unmodified argument. + */ + private FloatingNode baseCaseFloating(final FloatingNode f) { + if (f instanceof LogicNode) { + FloatingNode result = baseCaseLogicNode((LogicNode) f); + return rememberSubstitution(f, result); + } + return f; + } + + /** + * <p> + * Reduce the argument based on the state at the program point for it (ie, based on + * "valid facts" only, without relying on any floating-guard-assumption). + * </p> + * + * <p> + * The inputs of the argument aren't traversed into, for that + * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node) + * EquationalReasoner#deverbosify()} should be used instead. + * </p> + * <p> + * This method must behave as a function (idempotent query method): it should refrain from + * changing the state, as well as from updating caches (other than DebugMetric-s). + * </p> + * + * @return a {@link com.oracle.graal.nodes.LogicNode} different from the argument, in case a + * reduction was made. The node being returned might be already in the graph. In any + * case it's canonicalized already, the caller need not perform that again. In case no + * reduction was made, this method returns the unmodified argument. + * + */ + public FloatingNode baseCaseLogicNode(LogicNode condition) { + assert condition != null; + if (condition instanceof LogicConstantNode) { + return condition; + } else if (state.trueFacts.containsKey(condition)) { + metricEquationalReasoning.increment(); + return trueConstant; + } else if (state.falseFacts.containsKey(condition)) { + metricEquationalReasoning.increment(); + return falseConstant; + } else { + if (condition instanceof InstanceOfNode) { + return baseCaseInstanceOfNode((InstanceOfNode) condition); + } else if (condition instanceof IsNullNode) { + return baseCaseIsNullNode((IsNullNode) condition); + } else if (condition instanceof ObjectEqualsNode) { + return baseCaseObjectEqualsNode((ObjectEqualsNode) condition); + } + } + return condition; + } + + /** + * Actually the same result delivered by this method could be obtained by just letting + * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node) + * EquationalReasoner#deverbosify()} handle the argument in the default case for floating nodes + * (ie, deverbosify inputs followed by canonicalize). However it's done here for metrics + * purposes. + * + * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made; + * otherwise the unmodified argument. + * + */ + private LogicNode baseCaseInstanceOfNode(InstanceOfNode instanceOf) { + ValueNode scrutinee = GraphUtil.unproxify(instanceOf.object()); + if (!FlowUtil.hasLegalObjectStamp(scrutinee)) { + return instanceOf; + } + if (state.isNull(scrutinee)) { + metricInstanceOfRemoved.increment(); + return falseConstant; + } else if (state.isNonNull(scrutinee) && state.knownToConform(scrutinee, instanceOf.type())) { + metricInstanceOfRemoved.increment(); + return trueConstant; + } + return instanceOf; + } + + /** + * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was + * performed; otherwise the unmodified argument. + * + */ + private FloatingNode baseCaseIsNullNode(IsNullNode isNull) { + ValueNode object = isNull.object(); + if (!FlowUtil.hasLegalObjectStamp(object)) { + return isNull; + } + ValueNode scrutinee = GraphUtil.unproxify(isNull.object()); + GuardingNode evidence = nonTrivialNullAnchor(scrutinee); + if (evidence != null) { + metricNullCheckRemoved.increment(); + return trueConstant; + } else if (state.isNonNull(scrutinee)) { + metricNullCheckRemoved.increment(); + return falseConstant; + } + return isNull; + } + + /** + * @return a {@link com.oracle.graal.nodes.LogicConstantNode}, in case a reduction was made; + * otherwise the unmodified argument. + */ + private LogicNode baseCaseObjectEqualsNode(ObjectEqualsNode equals) { + if (!FlowUtil.hasLegalObjectStamp(equals.x()) || !FlowUtil.hasLegalObjectStamp(equals.y())) { + return equals; + } + ValueNode x = GraphUtil.unproxify(equals.x()); + ValueNode y = GraphUtil.unproxify(equals.y()); + if (state.isNull(x) && state.isNonNull(y) || state.isNonNull(x) && state.isNull(y)) { + metricObjectEqualsRemoved.increment(); + return falseConstant; + } else if (state.isNull(x) && state.isNull(y)) { + metricObjectEqualsRemoved.increment(); + return trueConstant; + } + return equals; + } + + /** + * It's always ok to use "<code>downcast(object)</code>" instead of " <code>object</code>" + * because this method re-wraps the argument in a {@link com.oracle.graal.nodes.PiNode} only if + * the new stamp is strictly more refined than the original. + * + * <p> + * This method does not + * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)} + * . + * </p> + * + * @return One of: + * <ul> + * <li>a {@link com.oracle.graal.nodes.PiNode} with more precise stamp than the input if + * the state warrants such downcasting</li> + * <li>a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} for the same + * scrutinee in question</li> + * <li>the unmodified argument otherwise.</li> + * </ul> + */ + ValueNode downcast(final ValueNode object) { + + // ------------------------------------------------- + // actions based only on the stamp of the input node + // ------------------------------------------------- + + if (!FlowUtil.hasLegalObjectStamp(object)) { + return object; + } + if (FlowUtil.isLiteralNode(object)) { + return object; + } + if (StampTool.isObjectAlwaysNull(object.stamp())) { + return nonTrivialNull(object); + } + + // ------------------------------------------ + // actions based on the stamp and the witness + // ------------------------------------------ + + ValueNode scrutinee = GraphUtil.unproxify(object); + + PiNode untrivialNull = nonTrivialNull(scrutinee); + if (untrivialNull != null) { + return untrivialNull; + } + + Witness w = state.typeInfo(scrutinee); + if (w == null) { + // no additional hints being tracked for the scrutinee + return object; + } + + assert !w.clueless(); + + ObjectStamp inputStamp = (ObjectStamp) object.stamp(); + ObjectStamp witnessStamp = w.asStamp(); + if (inputStamp.equals(witnessStamp) || !FlowUtil.isMorePrecise(witnessStamp, inputStamp)) { + // the witness offers no additional precision over current one + fixupTypeProfileStamp(object); + return object; + } + + assert !FlowUtil.isMorePrecise(inputStamp.type(), w.type()); + + ValueNode result; + if (object instanceof ValueProxy) { + result = downcastValueProxy((ValueProxy) object, w); + } else { + result = downcastedUtil(object, w); + } + + return result; + } + + /** + * TODO TypeProfileProxyNode.inferStamp doesn't infer non-null from non-null payload + * + * <p> + * And there's a bunch of asserts in + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} that assert no + * type-precision gets lost. Thus the need to fix-up on our own, as done here. + * </p> + */ + private static void fixupTypeProfileStamp(ValueNode object) { + if (!(object instanceof TypeProfileProxyNode)) { + return; + } + TypeProfileProxyNode profile = (TypeProfileProxyNode) object; + ObjectStamp outgoinStamp = (ObjectStamp) profile.stamp(); + ObjectStamp payloadStamp = (ObjectStamp) profile.getObject().stamp(); + if (payloadStamp.nonNull() && !outgoinStamp.nonNull()) { + profile.setStamp(FlowUtil.asNonNullStamp(outgoinStamp)); + } + } + + /** + * <p> + * Porcelain method. + * </p> + * + * <p> + * Utility to create, add to the graph, + * {@link EquationalReasoner#rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)} + * , and return a {@link com.oracle.graal.nodes.PiNode} that narrows into the given stamp, + * anchoring the payload. + * </p> + * + * <p> + * The resulting node might not have been in the graph already. + * </p> + */ + private PiNode wrapInPiNode(ValueNode payload, GuardingNode anchor, ObjectStamp newStamp, boolean remember) { + try (Debug.Scope s = Debug.scope("Downcast", payload)) { + assert payload != anchor : payload.graph().toString(); + metricDowncasting.increment(); + PiNode result = graph.unique(new PiNode(payload, newStamp, anchor.asNode())); + // we've possibly got a new node in the graph --- bookkeeping is in order. + added.add(result); + if (remember) { + rememberSubstitution(payload, result); + } + Debug.log("Downcasting from %s to %s", payload, result); + return result; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + /** + * <p> + * If the argument is known null due to its stamp, there's no need to have an anchor for that + * fact and this method returns null. + * </p> + * + * <p> + * Otherwise, if an anchor is found it is returned, null otherwise. + * </p> + */ + public GuardingNode nonTrivialNullAnchor(ValueNode object) { + assert FlowUtil.hasLegalObjectStamp(object); + if (StampTool.isObjectAlwaysNull(object)) { + return null; + } + return state.knownNull.get(GraphUtil.unproxify(object)); + } + + /** + * + * This method returns: + * <ul> + * <li><b>null</b>, if the argument is known null due to its stamp. Otherwise,</li> + * <li><b>a PiNode</b> wrapping the null constant and an anchor offering evidence as to why the + * argument is known null, if such anchor is available. Otherwise,</li> + * <li><b>null</b></li> + * </ul> + * <p> + * This method does not + * {@link #rememberSubstitution(com.oracle.graal.nodes.ValueNode, com.oracle.graal.nodes.ValueNode)} + * . + * </p> + */ + public PiNode nonTrivialNull(ValueNode object) { + assert FlowUtil.hasLegalObjectStamp(object); + GuardingNode anchor = nonTrivialNullAnchor(object); + if (anchor == null) { + return null; + } + if (object instanceof GuardedNode && StampTool.isObjectAlwaysNull(object.stamp())) { + return (PiNode) object; + } + // notice nullConstant is wrapped, not object + PiNode result = wrapInPiNode(nullConstant, anchor, (ObjectStamp) StampFactory.alwaysNull(), false); + return result; + } + + // @formatter:off + /** + * <p>ValueProxys can be classified along two dimensions, + * in addition to the fixed-floating dichotomy.</p> + * + * <p> + * First, we might be interested in separating those ValueProxys + * that are entitled to change (usually narrow) their stamp from those that aren't. + * In the first category are: + * PiNode, PiArrayNode, GuardingPiNode, + * CheckCastNode, UnsafeCastNode, and + * GuardedValueNode. + * </p> + * + * <p> + * A note on stamp-narrowing ValueProxys: + * our state abstraction tracks only the type refinements induced by CheckCastNode and GuardingPiNode + * (which are fixed nodes, unlike the other stamp-narrowing ValueProxys; + * the reason being that the state abstraction can be updated only at fixed nodes). + * As a result, the witness for a (PiNode, PiArrayNode, UnsafeCastNode, or GuardedValueNode) + * may be less precise than the proxy's stamp. We don't want to lose such precision, + * thus <code>downcast(proxy) == proxy</code> in such cases. + * </p> + * + * <p> + * The second classification focuses on + * the additional information that travels with the proxy + * (in addition to its "payload", ie getOriginalValue(), and any narrowing-stamp). + * Such additional information boils down to: + * + * (a) type profile (TypeProfileProxyNode) + * (b) type profile (CheckCastNode) + * (c) anchor (GuardedValueNode) + * (d) anchor (PiNode) + * (e) anchor and array length (PiArrayNode) + * (f) optional anchor (UnsafeCastNode) + * (g) deopt-condition (GuardingPiNode) + * (h) LocationIdentity (MemoryProxyNOde) + * (i) control-flow dependency (FixedValueAnchorNode) + * (j) proxyPoint (ProxyNode -- think loops) + *</p> + */ + // @formatter:on + private ValueNode downcastValueProxy(ValueProxy proxy, Witness w) { + assert FlowUtil.hasLegalObjectStamp((ValueNode) proxy); + assert FlowUtil.hasLegalObjectStamp((proxy).getOriginalNode()); + assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify(proxy.getOriginalNode()); + + assert GraphUtil.unproxify((ValueNode) proxy) == GraphUtil.unproxify((proxy).getOriginalNode()); + + if (proxy instanceof PiNode) { + return downcastPiNodeOrPiArrayNode((PiNode) proxy, w); + } else if (proxy instanceof GuardingPiNode) { + return downcastGuardingPiNode((GuardingPiNode) proxy, w); + } else if (proxy instanceof TypeProfileProxyNode) { + return downcastTypeProfileProxyNode((TypeProfileProxyNode) proxy); + } else if (proxy instanceof CheckCastNode) { + return downcastCheckCastNode((CheckCastNode) proxy, w); + } else if (proxy instanceof ProxyNode || proxy instanceof GuardedValueNode) { + // TODO scaladacapo return downcastedUtil((ValueNode) proxy, w); + return (ValueNode) proxy; + } + + assert false : "TODO case not yet handled"; + + // TODO complete the missing implementation for the cases not yet handled + + return ((ValueNode) proxy); + } + + /** + * <p> + * Why would we want to downcast a GuardingPiNode? Is it even possible? Like, for example, a + * GuardingPiNode originating in the lowering of a CheckCastNode (carried out by + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode) + * visitCheckCastNode()}). + * </p> + * + * <p> + * It's both possible and desirable. Example: <code> + * Number n = (Number) o; + * if (n instanceof Integer) { + * return n.intValue(); + * } + * </code> + * + * The receiver of intValue() is a usage of a previous checkCast, for which the current witness + * provides a more refined type (and an anchor). In this case, the advantage of downcasting a + * GuardingPiNode is clear: devirtualizing the `intValue()` callsite. + * </p> + * + * @see #downcastValueProxy + */ + public ValueNode downcastGuardingPiNode(GuardingPiNode envelope, Witness w) { + assert envelope != w.guard().asNode() : "The stamp of " + envelope + " would lead to downcasting with that very same GuardingPiNode as guard."; + return downcastedUtil(envelope, w); + } + + /** + * <p> + * This method accepts both {@link com.oracle.graal.nodes.PiNode} and + * {@link com.oracle.graal.nodes.PiArrayNode} argument. + * </p> + * + * <p> + * In case a witness reveals a strictly more precise type than the + * {@link com.oracle.graal.nodes.PiNode}'s stamp, this method wraps the argument in a new + * {@link com.oracle.graal.nodes.PiNode} with updated stamp, and returns it. + * </p> + * + * <p> + * A {@link com.oracle.graal.nodes.PiArrayNode} argument ends up wrapped in a + * {@link com.oracle.graal.nodes.PiNode}. Thus, the + * {@link com.oracle.graal.nodes.PiArrayNode#length} information doesn't get lost. + * </p> + * + * <p> + * Note: {@link com.oracle.graal.nodes.PiNode}'s semantics allow un-packing its payload as soon + * as it type conforms to that of the {@link com.oracle.graal.nodes.PiNode} (that's what + * {@link com.oracle.graal.nodes.PiNode#canonical(com.oracle.graal.graph.spi.CanonicalizerTool) + * PiNode.canonical()} does). Not clear the benefits of duplicating that logic here. + * </p> + * + * @see #downcastValueProxy + */ + private ValueNode downcastPiNodeOrPiArrayNode(PiNode envelope, Witness w) { + return downcastedUtil(envelope, w); + } + + /** + * <p> + * In a case the payload of the {@link com.oracle.graal.nodes.TypeProfileProxyNode} can be + * downcasted, this method returns a copy-on-write version with the downcasted payload. + * </p> + * + * <p> + * Otherwise returns the unmodified argument. + * </p> + * + * @see #downcastValueProxy + */ + private ValueNode downcastTypeProfileProxyNode(TypeProfileProxyNode envelope) { + ValueNode payload = envelope.getOriginalNode(); + ValueNode d = downcast(payload); + if (payload != d) { + TypeProfileProxyNode changed = (TypeProfileProxyNode) envelope.copyWithInputs(); + added.add(changed); + // copyWithInputs() implies graph.unique(changed) + FlowUtil.replaceInPlace(changed, payload, d); + FlowUtil.inferStampAndCheck(changed); + fixupTypeProfileStamp(changed); + /* + * It's not prudent to (1) obtain the canonical() of the (changed) TypeProfileProxyNode + * to (2) replace its usages; because we're potentially walking a DAG (after all, + * TypeProfileProxyNode is a floating-node). Those steps, which admittedly are needed, + * are better performed upon replacing in-place the inputs of a FixedNode, or during + * Canonicalize. + */ + return changed; + } + fixupTypeProfileStamp(envelope); + return envelope; + } + + /** + * <p> + * Re-wrap the checkCast in a type-refining {@link com.oracle.graal.nodes.PiNode PiNode} only if + * the downcasted scrutinee does not conform to the checkCast's target-type. + * </p> + */ + private ValueNode downcastCheckCastNode(CheckCastNode checkCast, Witness w) { + + final ResolvedJavaType toType = checkCast.type(); + + if (checkCast.object() instanceof CheckCastNode) { + ValueNode innerMost = checkCast; + while (innerMost instanceof CheckCastNode) { + innerMost = ((CheckCastNode) innerMost).object(); + } + ValueNode deepest = downcast(innerMost); + ResolvedJavaType deepestType = ((ObjectStamp) deepest.stamp()).type(); + if ((deepestType != null && deepestType.equals(toType)) || FlowUtil.isMorePrecise(deepestType, toType)) { + assert !w.knowsBetterThan(deepest); + return deepest; + } + } + + ValueNode subject = downcast(checkCast.object()); + ObjectStamp subjectStamp = (ObjectStamp) subject.stamp(); + ResolvedJavaType subjectType = subjectStamp.type(); + + if (subjectType != null && toType.isAssignableFrom(subjectType)) { + assert !w.knowsBetterThan(subject); + return subject; + } + + return downcastedUtil(checkCast, w); + } + + /** + * <p> + * Porcelain method. + * </p> + * + * <p> + * This method wraps the argument in a new {@link com.oracle.graal.nodes.PiNode PiNode} (created + * to hold an updated stamp) provided the argument's stamp can be strictly refined, and returns + * it. + * </p> + */ + private ValueNode downcastedUtil(ValueNode subject, Witness w) { + + ObjectStamp originalStamp = (ObjectStamp) subject.stamp(); + ObjectStamp outgoingStamp = originalStamp; + + if (w.isNonNull() && !outgoingStamp.nonNull()) { + outgoingStamp = FlowUtil.asNonNullStamp(outgoingStamp); + } + if (FlowUtil.isMorePrecise(w.type(), outgoingStamp.type())) { + outgoingStamp = FlowUtil.asRefinedStamp(outgoingStamp, w.type()); + } + + if (outgoingStamp != originalStamp) { + assert FlowUtil.isMorePrecise(outgoingStamp, originalStamp); + + boolean isWitnessGuardAnAliasForScrutinee = false; + if (w.guard() instanceof GuardingPiNode || w.guard() instanceof PiNode) { + /* + * The guard offered by the witness canonicalizes into its subject (a possibly + * type-refined scrutinee) provided its subject conforms as per stamp. + */ + if (w.guard().asNode().stamp().equals(outgoingStamp)) { + isWitnessGuardAnAliasForScrutinee = true; + } + } + + ValueNode result; + if (isWitnessGuardAnAliasForScrutinee) { + result = w.guard().asNode(); + assert !w.knowsBetterThan(result); + return result; // TODO this works. explain why. + } else { + result = wrapInPiNode(subject, w.guard(), outgoingStamp, true); + assert !w.knowsBetterThan(result); + return result; + } + + } else { + assert !w.knowsBetterThan(subject); + return subject; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,218 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.IsNullNode; +import com.oracle.graal.nodes.extended.GuardingNode; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.tiers.PhaseContext; + +/** + * <p> + * This class implements control-flow sensitive reductions for + * {@link com.oracle.graal.nodes.FixedGuardNode}. + * </p> + * + * @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode) + */ +public abstract class FixedGuardReduction extends CheckCastReduction { + + public FixedGuardReduction(FixedNode start, State initialState, PhaseContext context) { + super(start, initialState, context); + } + + /** + * In case the condition is constant, + * {@link com.oracle.graal.nodes.FixedGuardNode#simplify(com.oracle.graal.graph.spi.SimplifierTool) + * FixedGuardNode#simplify(SimplifierTool)} will eventually remove the + * {@link com.oracle.graal.nodes.FixedGuardNode} ("always succeeds") or kill the code that + * should be killed ("always fails"). + * + * <p> + * The only thing we do here is tracking as true fact (from this program point onwards) the + * condition of the {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}. + * </p> + * + * <p> + * Precondition: the condition hasn't been deverbosified yet. + * </p> + */ + protected final void visitFixedGuardNode(FixedGuardNode f) { + + /* + * A FixedGuardNode with LogicConstantNode condition is left untouched. + */ + + if (f.condition() instanceof LogicConstantNode) { + if (FlowUtil.alwaysFails(f.isNegated(), f.condition())) { + state.impossiblePath(); + // let FixedGuardNode(false).simplify() prune the dead-code control-path + return; + } + assert FlowUtil.alwaysSucceeds(f.isNegated(), f.condition()); + return; + } + + /* + * Attempt to eliminate the current FixedGuardNode by using another GuardingNode already in + * scope and with equivalent condition. + */ + + GuardingNode existingGuard = f.isNegated() ? state.falseFacts.get(f.condition()) : state.trueFacts.get(f.condition()); + if (existingGuard != null) { + // assert existingGuard instanceof FixedGuardNode; + metricFixedGuardNodeRemoved.increment(); + f.replaceAtUsages(existingGuard.asNode()); + graph.removeFixed(f); + return; + } + + final LogicNode cond = f.condition(); + final boolean isTrue = !f.isNegated(); + + /* + * FixedGuardNode requires handling similar to that of GuardingPiNode, (ie the condition + * can't simply be deverbosified in place). A replacement anchor is needed, ie an anchor + * that amounts to the same combination of (negated, condition) for the FixedGuardNode at + * hand. + */ + + // TODO what about isDependencyTainted + + if (cond instanceof IsNullNode) { + final IsNullNode isNullNode = (IsNullNode) cond; + if (isTrue) { + // grab an anchor attesting nullness + final GuardingNode replacement = reasoner.nonTrivialNullAnchor(isNullNode.object()); + if (replacement != null) { + removeFixedGuardNode(f, replacement); + return; + } + if (state.isNonNull(isNullNode.object())) { + markFixedGuardNodeAlwaysFails(f); + return; + } + // can't produce evidence, fall-through to addFact + } else { + // grab an anchor attesting non-nullness + final Witness w = state.typeInfo(isNullNode.object()); + if (w != null && w.isNonNull()) { + removeFixedGuardNode(f, w.guard()); + return; + } + if (state.isNull(isNullNode.object())) { + markFixedGuardNodeAlwaysFails(f); + return; + } + // can't produce evidence, fall-through to addFact + } + } else if (cond instanceof InstanceOfNode) { + final InstanceOfNode iOf = (InstanceOfNode) cond; + final Witness w = state.typeInfo(iOf.object()); + if (isTrue) { + // grab an anchor attesting instanceof + if (w != null) { + if (w.isNonNull() && w.type() != null) { + if (iOf.type().isAssignableFrom(w.type())) { + removeFixedGuardNode(f, w.guard()); + return; + } + if (State.knownNotToConform(w.type(), iOf.type())) { + markFixedGuardNodeAlwaysFails(f); + return; + } + } + } + if (state.isNull(iOf.object())) { + markFixedGuardNodeAlwaysFails(f); + return; + } + // can't produce evidence, fall-through to addFact + } else { + // grab an anchor attesting not-instanceof + // (1 of 2) attempt determining nullness + final GuardingNode nullGuard = reasoner.nonTrivialNullAnchor(iOf.object()); + if (nullGuard != null) { + removeFixedGuardNode(f, nullGuard); + return; + } + // (2 of 2) attempt determining known-not-to-conform + if (w != null && !w.cluelessAboutType()) { + if (State.knownNotToConform(w.type(), iOf.type())) { + removeFixedGuardNode(f, w.guard()); + return; + } + } + // can't produce evidence, fall-through to addFact + } + } else if (isTrue && cond instanceof ShortCircuitOrNode) { + CastCheckExtractor cce = CastCheckExtractor.extract(cond); + if (cce != null && !State.isDependencyTainted(cce.subject, f)) { + // grab an anchor attesting check-cast + Witness w = state.typeInfo(cce.subject); + if (w != null && w.type() != null) { + if (cce.type.isAssignableFrom(w.type())) { + removeFixedGuardNode(f, w.guard()); + return; + } + if (State.knownNotToConform(w.type(), cce.type)) { + markFixedGuardNodeAlwaysFails(f); + return; + } + } + } + // can't produce evidence, fall-through to addFact + } + + state.addFact(isTrue, cond, f); + } + + /** + * Porcelain method. + */ + private void markFixedGuardNodeAlwaysFails(FixedGuardNode f) { + metricFixedGuardNodeRemoved.increment(); + state.impossiblePath(); + f.setCondition(f.isNegated() ? trueConstant : falseConstant); + // `f.condition()` if unused will be removed in finished() + } + + /** + * Porcelain method. + * + * <p> + * The `replacement` guard must be such that it implies the `old` guard. + * </p> + */ + private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) { + if (replacement == null) { + return; + } + metricFixedGuardNodeRemoved.increment(); + old.replaceAtUsages(replacement.asNode()); + graph.removeFixed(old); + // `old.condition()` if unused will be removed in finished() + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,545 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.FloatingNode; +import com.oracle.graal.nodes.extended.LoadHubNode; +import com.oracle.graal.nodes.extended.NullCheckNode; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.compiler.common.type.IllegalStamp; +import com.oracle.graal.nodes.type.StampTool; +import com.oracle.graal.nodes.util.GraphUtil; +import com.oracle.graal.phases.common.DeadCodeEliminationPhase; +import com.oracle.graal.phases.tiers.PhaseContext; + +import java.lang.reflect.Modifier; + +import static com.oracle.graal.api.meta.DeoptimizationReason.*; + +/** + * <p> + * All control-flow-sensitive reductions follow the common pattern of + * <ul> + * <li>Recognizing properties of interest (ie, LogicNode-s) at control-flow splits, as well as upon + * check-casts and fixed-guards.</li> + * <li>Using the information thus tracked to simplify + * <ul> + * <li>side-effects free expressions, via + * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)} + * </li> + * <li>control-flow, eg. by eliminating redundant fixed-guards and check-casts, ie which are known + * always to hold.</li> + * </ul> + * </li> + * </ul> + * </p> + * + * @see com.oracle.graal.phases.common.cfs.CheckCastReduction + * @see com.oracle.graal.phases.common.cfs.GuardingPiReduction + * @see com.oracle.graal.phases.common.cfs.FixedGuardReduction + * + */ +public class FlowSensitiveReduction extends FixedGuardReduction { + + public FlowSensitiveReduction(FixedNode start, State initialState, PhaseContext context) { + super(start, initialState, context); + } + + /** + * <p> + * This method performs two kinds of cleanup: + * <ol> + * <li> + * marking as unreachable certain code-paths, as described in + * {@link com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt}</li> + * <li> + * Removing nodes not in use that were added during this phase, as described next.</li> + * </ol> + * </p> + * + * + * <p> + * Methods like + * {@link com.oracle.graal.phases.common.cfs.FlowUtil#replaceInPlace(com.oracle.graal.graph.Node, com.oracle.graal.graph.Node, com.oracle.graal.graph.Node)} + * may result in old inputs becoming disconnected from the graph. It's not advisable to + * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} at + * that moment, because one of the inputs that might get killed is one of {@link #nullConstant}, + * {@link #falseConstant}, or {@link #trueConstant}; which thus could get killed too early, + * before another invocation of + * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)} + * needs them. To recap, + * {@link com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} also + * recursively visits the inputs of the its argument. + * </p> + * + * <p> + * This method goes over all of the nodes that deverbosification might have added, which are + * either: + * <ul> + * <li> + * {@link com.oracle.graal.nodes.calc.FloatingNode}, added by + * {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosifyFloatingNode(com.oracle.graal.nodes.calc.FloatingNode)} + * ; or</li> + * <li> + * {@link com.oracle.graal.nodes.java.MethodCallTargetNode}, added by + * {@link #deverbosifyInputsCopyOnWrite(com.oracle.graal.nodes.java.MethodCallTargetNode)}</li> + * </ul> + * + * Checking if they aren't in use, proceeding to remove them in that case. + * </p> + * + */ + @Override + public void finished() { + if (!postponedDeopts.isEmpty()) { + for (PostponedDeopt postponed : postponedDeopts) { + postponed.doRewrite(falseConstant); + } + new DeadCodeEliminationPhase().apply(graph); + } + for (MethodCallTargetNode mcn : graph.getNodes().filter(MethodCallTargetNode.class)) { + if (mcn.isAlive() && FlowUtil.lacksUsages(mcn)) { + mcn.safeDelete(); + } + } + for (Node n : graph.getNodes().filter(FloatingNode.class)) { + GraphUtil.tryKillUnused(n); + } + assert !isAliveWithoutUsages(trueConstant); + assert !isAliveWithoutUsages(falseConstant); + assert !isAliveWithoutUsages(nullConstant); + } + + private static boolean isAliveWithoutUsages(FloatingNode node) { + return node.isAlive() && node.usages().isEmpty(); + } + + private void registerControlSplit(Node pred, BeginNode begin) { + assert pred != null && begin != null; + assert !state.isUnreachable; + + if (begin instanceof LoopExitNode) { + state.clear(); + } + + if (pred instanceof IfNode) { + registerIfNode((IfNode) pred, begin); + } else if (pred instanceof TypeSwitchNode) { + registerTypeSwitchNode((TypeSwitchNode) pred, begin); + } + } + + private void registerIfNode(IfNode ifNode, BeginNode begin) { + final boolean isThenBranch = (begin == ifNode.trueSuccessor()); + + if (ifNode.condition() instanceof LogicConstantNode) { + final LogicConstantNode constCond = (LogicConstantNode) ifNode.condition(); + if (isThenBranch != constCond.getValue()) { + state.impossiblePath(); + // let IfNode(constant) prune the dead-code control-path + } + } + + if (state.isUnreachable) { + if (!(ifNode.condition() instanceof LogicConstantNode)) { + // if condition constant, no need to add a Deopt node + postponedDeopts.addDeoptAfter(begin, UnreachedCode); + } + } else { + state.addFact(isThenBranch, ifNode.condition(), begin); + } + } + + /** + * TODO When tracking integer-stamps, the state at each successor of a TypeSwitchNode should + * track an integer-stamp for the LoadHubNode (meet over the constants leading to that + * successor). However, are LoadHubNode-s shared frequently enough? + */ + private void registerTypeSwitchNode(TypeSwitchNode typeSwitch, BeginNode begin) { + if (typeSwitch.value() instanceof LoadHubNode) { + LoadHubNode loadHub = (LoadHubNode) typeSwitch.value(); + ResolvedJavaType type = null; + for (int i = 0; i < typeSwitch.keyCount(); i++) { + if (typeSwitch.keySuccessor(i) == begin) { + if (type == null) { + type = typeSwitch.typeAt(i); + } else { + type = FlowUtil.widen(type, typeSwitch.typeAt(i)); + } + } + } + if (type == null) { + // `begin` denotes the default case of the TypeSwitchNode + return; + } + // preferable would be trackExact, but not there yet + state.addNullness(false, loadHub.object(), begin); + if (state.knownNotToConform(loadHub.object(), type)) { + postponedDeopts.addDeoptAfter(begin, UnreachedCode); + state.impossiblePath(); + return; + } + if (type.isInterface()) { + state.trackNN(loadHub.object(), begin); + } else { + state.trackIO(loadHub.object(), type, begin); + } + } + } + + /** + * + * <p> + * Reduce input nodes based on the state at the program point for the argument (ie, based on + * "valid facts" only, without relying on any floating-guard-assumption). + * </p> + * + * <p> + * For each (direct or indirect) child, a copy-on-write version is made in case any of its + * children changed, with the copy accommodating the updated children. If the parent was shared, + * copy-on-write prevents the updates from becoming visible to anyone but the invoker of this + * method. + * </p> + * + * <p> + * <b> Please note the parent node is mutated upon any descendant changing. No copy-on-write is + * performed for the parent node itself. </b> + * </p> + * + * <p> + * In more detail, for each direct {@link com.oracle.graal.nodes.ValueNode} input of the node at + * hand, + * + * <ol> + * <li> + * Obtain a lazy-copied version (via spanning tree) of the DAG rooted at the input-usage in + * question. Lazy-copying is done by walking a spanning tree of the original DAG, stopping at + * non-FloatingNodes but transitively walking FloatingNodes and their inputs. Upon arriving at a + * (floating) node N, the state's facts are checked to determine whether a constant C can be + * used instead in the resulting lazy-copied DAG. A NodeBitMap is used to realize the spanning + * tree.</li> + * + * <li> + * Provided one or more N-to-C node replacements took place, the resulting lazy-copied DAG has a + * parent different from the original (ie different object identity) which indicates the + * (copied, updated) DAG should replace the original via replaceFirstInput(), and inferStamp() + * should be invoked to reflect the updated inputs.</li> + * + * </ol> + * </p> + * + * @return whether any reduction was performed on the inputs of the arguments. + */ + public boolean deverbosifyInputsInPlace(ValueNode parent) { + boolean changed = false; + for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) { + assert !(i instanceof GuardNode) : "ConditionalElim shouldn't run in MidTier"; + ValueNode j = (ValueNode) reasoner.deverbosify(i); + if (i != j) { + changed = true; + FlowUtil.replaceInPlace(parent, i, j); + } + } + if (changed) { + FlowUtil.inferStampAndCheck(parent); + } + return changed; + } + + /** + * Similar to {@link #deverbosifyInputsInPlace(com.oracle.graal.nodes.ValueNode)}, except that + * not the parent but a fresh clone is updated upon any of its children changing. + * + * @return the original parent if no updated took place, a copy-on-write version of it + * otherwise. + * + */ + private MethodCallTargetNode deverbosifyInputsCopyOnWrite(MethodCallTargetNode parent) { + MethodCallTargetNode changed = null; + for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) { + Node j = reasoner.deverbosify(i); + if (i != j) { + assert j != parent; + if (changed == null) { + changed = (MethodCallTargetNode) parent.copyWithInputs(); + reasoner.added.add(changed); + // copyWithInputs() implies graph.unique(changed) + assert changed.isAlive(); + assert FlowUtil.lacksUsages(changed); + } + FlowUtil.replaceInPlace(changed, i, j); + } + } + if (changed == null) { + return parent; + } + FlowUtil.inferStampAndCheck(changed); + /* + * No need to rememberSubstitution() because not called from deverbosify(). In detail, it's + * only deverbosify() that skips visited nodes (thus we'd better have recorded any + * substitutions we want for them). Not this case. + */ + return changed; + } + + /** + * Precondition: This method assumes that either: + * + * <ul> + * <li>the state has already stabilized (ie no more pending iterations in the "iterative" + * dataflow algorithm); or</li> + * <li>any rewritings made based on the state in its current form are conservative enough to be + * safe.</li> + * </ul> + * + * <p> + * The overarching goal is to perform just enough rewriting to trigger other phases ( + * {@link com.oracle.graal.graph.spi.SimplifierTool SimplifierTool}, + * {@link com.oracle.graal.phases.common.DeadCodeEliminationPhase DeadCodeEliminationPhase}, + * etc) to perform the bulk of rewriting, thus lowering the maintenance burden. + * </p> + * + */ + @Override + protected void node(FixedNode node) { + + assert node.isAlive(); + + /*------------------------------------------------------------------------------------- + * Step 1: Unreachable paths are still visited (PostOrderNodeIterator requires all ends + * of a merge to have been visited), but time is saved by neither updating the state nor + * rewriting anything while on an an unreachable path. + *------------------------------------------------------------------------------------- + */ + if (state.isUnreachable) { + return; + } + + /*------------------------------------------------------------------------------------- + * Step 2: For an AbstractBeginNode, determine whether this path is reachable, register + * any associated guards. + *------------------------------------------------------------------------------------- + */ + if (node instanceof BeginNode) { + BeginNode begin = (BeginNode) node; + Node pred = node.predecessor(); + + if (pred != null) { + registerControlSplit(pred, begin); + } + return; + } + + /*------------------------------------------------------------------------------------- + * Step 3: Check whether EquationalReasoner caches should be cleared upon state updates. + *------------------------------------------------------------------------------------- + */ + reasoner.updateState(state); + + /*------------------------------------------------------------------------------------- + * Step 4: Whatever special-case handling makes sense for the FixedNode at hand before + * its inputs are reduced. + *------------------------------------------------------------------------------------- + */ + + if (node instanceof AbstractEndNode) { + visitAbstractEndNode((AbstractEndNode) node); + return; + } else if (node instanceof Invoke) { + visitInvoke((Invoke) node); + return; + } else if (node instanceof CheckCastNode) { + // it's important not to call deverbosification for visitCheckCastNode() + visitCheckCastNode((CheckCastNode) node); + return; + } else if (node instanceof GuardingPiNode) { + visitGuardingPiNode((GuardingPiNode) node); + return; + } else if (node instanceof NullCheckNode) { + visitNullCheckNode((NullCheckNode) node); + return; + } else if (node instanceof FixedGuardNode) { + visitFixedGuardNode((FixedGuardNode) node); + return; + } else if (node instanceof ConditionAnchorNode) { + // ConditionAnchorNode shouldn't occur during HighTier + return; + } + + /*------------------------------------------------------------------------------------- + * Step 5: After special-case handling, we do our best for those FixedNode-s + * where the effort to reduce their inputs might pay off. + * + * Why is this useful? For example, by the time the AbstractBeginNode for an If-branch + * is visited (in general a ControlSplitNode), the If-condition will have gone already + * through simplification (and thus potentially have been reduced to a + * LogicConstantNode). + *------------------------------------------------------------------------------------- + */ + boolean paysOffToReduce = false; + if (node instanceof ControlSplitNode) { + // desire to simplify control flow + paysOffToReduce = true; + } else if (node instanceof ReturnNode) { + paysOffToReduce = true; + } else if (node instanceof AccessFieldNode || node instanceof AccessArrayNode) { + // desire to remove null-checks + paysOffToReduce = true; + } + + // TODO comb the remaining FixedWithNextNode subclasses, pick those with good changes of + // paying-off + + // TODO UnsafeLoadNode takes a condition + + if (paysOffToReduce) { + deverbosifyInputsInPlace(node); + } + + /*--------------------------------------------------------------------------------------- + * Step 6: Any additional special-case handling, this time after having inputs reduced. + * For example, leverage anchors provided by the FixedNode, to add facts to the factbase. + *--------------------------------------------------------------------------------------- + */ + + // TODO some nodes are GuardingNodes (eg, FixedAccessNode) we could use them to track state + // TODO others are additionally guarded (eg JavaReadNode), thus *their* guards could be + // simplified. + + } + + /** + * In case the scrutinee: + * + * <ul> + * <li>is known to be null, an unconditional deopt is added.</li> + * <li>is known to be non-null, the NullCheckNode is removed.</li> + * </ul> + * + * <p> + * Precondition: the input (ie, object) hasn't been deverbosified yet. + * </p> + */ + private void visitNullCheckNode(NullCheckNode ncn) { + ValueNode object = ncn.getObject(); + if (state.isNull(object)) { + postponedDeopts.addDeoptBefore(ncn, NullCheckException); + state.impossiblePath(); + return; + } + if (state.isNonNull(object)) { + /* + * Redundant NullCheckNode. Unlike GuardingPiNode or FixedGuardNode, NullCheckNode-s + * aren't used as GuardingNode-s, thus in this case can be removed without further ado. + */ + assert FlowUtil.lacksUsages(ncn); + graph.removeFixed(ncn); + return; + } + // TODO ANCHOR NEEDED: state.trackNN(object, ncn); + } + + /** + * The {@link com.oracle.graal.nodes.AbstractEndNode} at the end of the current code path + * contributes values to {@link com.oracle.graal.nodes.PhiNode}s. Now is a good time to + * {@link EquationalReasoner#deverbosify(com.oracle.graal.graph.Node) + * EquationalReasoner#deverbosify} those values. + * + * <p> + * Precondition: inputs haven't been deverbosified yet. + * </p> + */ + private void visitAbstractEndNode(AbstractEndNode endNode) { + MergeNode merge = endNode.merge(); + for (PhiNode phi : merge.phis()) { + if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) { + assert phi.verify(); + int index = merge.phiPredecessorIndex(endNode); + ValueNode original = phi.valueAt(index); + ValueNode reduced = (ValueNode) reasoner.deverbosify(original); + if (reduced != original) { + phi.setValueAt(index, reduced); + // `original` if unused will be removed in finished() + } + } + } + } + + /** + * One or more arguments at `invoke` may have control-flow sensitive simplifications. In such + * case, a new {@link com.oracle.graal.nodes.java.MethodCallTargetNode MethodCallTargetNode} is + * prepared just for this callsite, consuming reduced arguments. This proves useful in + * connection with inlining, in order to specialize callees on the types of arguments other than + * the receiver (examples: multi-methods, the inlining problem, lambdas as arguments). + * + * <p> + * Precondition: inputs haven't been deverbosified yet. + * </p> + */ + private void visitInvoke(Invoke invoke) { + if (invoke.asNode().stamp() instanceof IllegalStamp) { + return; // just to be safe + } + boolean isMethodCallTarget = invoke.callTarget() instanceof MethodCallTargetNode; + if (!isMethodCallTarget) { + return; + } + FlowUtil.replaceInPlace(invoke.asNode(), invoke.callTarget(), deverbosifyInputsCopyOnWrite((MethodCallTargetNode) invoke.callTarget())); + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + if (callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != MethodCallTargetNode.InvokeKind.Virtual) { + return; + } + ValueNode receiver = callTarget.receiver(); + if (receiver == null) { + return; + } + if (!FlowUtil.hasLegalObjectStamp(receiver)) { + return; + } + Witness w = state.typeInfo(receiver); + ResolvedJavaType type; + ResolvedJavaType stampType = StampTool.typeOrNull(receiver); + if (w == null || w.cluelessAboutType()) { + // can't improve on stamp but wil try to devirtualize anyway + type = stampType; + } else { + type = FlowUtil.tighten(w.type(), stampType); + } + if (type == null) { + return; + } + ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod()); + if (method == null) { + return; + } + if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) { + metricMethodResolved.increment(); + callTarget.setInvokeKind(MethodCallTargetNode.InvokeKind.Special); + callTarget.setTargetMethod(method); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,54 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.PhaseContext; + +public class FlowSensitiveReductionPhase extends BasePhase<PhaseContext> { + + private final MetaAccessProvider metaAccess; + + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + public FlowSensitiveReductionPhase(MetaAccessProvider metaAccess) { + this.metaAccess = metaAccess; + } + + @Override + protected final void run(StructuredGraph graph, PhaseContext context) { + try (Debug.Scope s = Debug.scope("FlowSensitiveReduction")) { + Debug.dump(graph, "FlowSensitiveReduction initial"); + new FlowSensitiveReduction(graph.start(), new State(), context).apply(); + Debug.dump(graph, "FlowSensitiveReduction done"); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,317 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.ResolvedJavaType; +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugConfig; +import com.oracle.graal.debug.DebugConfigScope; +import com.oracle.graal.debug.internal.DebugScope; +import com.oracle.graal.graph.InputType; +import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.NodeClass; +import com.oracle.graal.nodes.*; +import com.oracle.graal.compiler.common.type.ObjectStamp; +import com.oracle.graal.compiler.common.type.Stamp; +import com.oracle.graal.compiler.common.type.StampFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FlowUtil { + + private FlowUtil() { + // no instances of this class + } + + public static boolean lacksUsages(Node n) { + return n.recordsUsages() && n.usages().isEmpty(); + } + + public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) { + if (a == null || b == null) { + return null; + } else if (a.equals(b)) { + return a; + } else { + return a.findLeastCommonAncestor(b); + } + } + + /** + * @return whether the first argument is strictly more precise than the second. + */ + public static boolean isMorePrecise(ResolvedJavaType a, ResolvedJavaType b) { + if (a == null) { + return false; + } + if (b == null) { + return true; + } + assert !a.isPrimitive(); + assert !b.isPrimitive(); + if (a.equals(b)) { + return false; + } + if (b.isInterface()) { + return b.isAssignableFrom(a); + } + if (a.isInterface()) { + return b.isInterface() && b.isAssignableFrom(a); + } + return b.isAssignableFrom(a); + } + + public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) { + if (a == null) { + assert b == null || !b.isPrimitive(); + return b; + } + if (b == null) { + assert !a.isPrimitive(); + return a; + } + assert !a.isPrimitive(); + assert !b.isPrimitive(); + if (a.equals(b)) { + return a; + } + if (isMorePrecise(a, b)) { + return a; + } else if (isMorePrecise(b, a)) { + return b; + } else { + /* + * Not comparable, two cases: + * + * Example 1: 'a' standing for j.l.Number and 'b' for j.l.String We return null for lack + * of a value representing NullType, the right answer. Same goes when both arguments are + * non-comparable interfaces. + * + * Example 2: 'a' standing for sun/nio/ch/DirectBuffer (an interface) and b for + * java/nio/Buffer (an abstract class). The class always takes precedence. + */ + if (a.isInterface()) { + return b.isInterface() ? null : b; + } + if (b.isInterface()) { + return a.isInterface() ? null : a; + } + return null; // a and b aren't comparable, can't tighten() them + } + } + + /** + * + * There are "illegal" stamps that are not of type IllegalStamp. + * + * For example, there may be an IntegerStamp with upperBound < lowerBound that returns + * !isLegal() but we still know it's an integer and thus not of type IllegalStamp. + * + * An IllegalStamp should never happen. In contrast, !isLegal() values could happen due to dead + * code not yet removed, or upon some non-sideeffecting instructions floating out of a dead + * branch. + */ + public static boolean isLegalObjectStamp(Stamp s) { + return isObjectStamp(s) && s.isLegal(); + } + + public static boolean hasLegalObjectStamp(ValueNode v) { + return isLegalObjectStamp(v.stamp()); + } + + public static boolean isObjectStamp(Stamp stamp) { + return stamp instanceof ObjectStamp; + } + + public static void inferStampAndCheck(ValueNode n) { + n.inferStamp(); + if (n.stamp() instanceof ObjectStamp) { + ObjectStamp objectStamp = (ObjectStamp) n.stamp(); + assert !objectStamp.isExactType() || objectStamp.type() != null; + } + } + + /** + * Compares the arguments along three dimensions (nullness, exactness, and type). For the first + * argument to be more precise than the second, it may not score lower in any dimension and must + * score higher in at least one dimension. + * + * When comparing types s and t, sameness counts as 0; while being more precise is awarded with + * a score of 1. In all other cases (non-comparable, or supertype) the score is -1. + * + * @return whether the first argument is strictly more precise than the second. + */ + public static boolean isMorePrecise(ObjectStamp a, ObjectStamp b) { + int d0 = MINUS(a.alwaysNull(), b.alwaysNull()); + if (d0 == -1) { + return false; + } + int d1 = MINUS(a.nonNull(), b.nonNull()); + if (d1 == -1) { + return false; + } + int d2 = MINUS(a.isExactType(), b.isExactType()); + if (d2 == -1) { + return false; + } + int d3; + ResolvedJavaType ta = a.type(); + ResolvedJavaType tb = b.type(); + if (ta == null) { + d3 = (tb == null) ? 0 : -1; + } else if (tb == null) { + d3 = 1; + } else if (isMorePrecise(ta, tb)) { + d3 = 1; + } else if (ta.equals(tb)) { + d3 = 0; + } else { + d3 = -1; + } + if (d3 == -1) { + return false; + } + int maxScore = Math.max(Math.max(d0, d1), Math.max(d2, d3)); + return maxScore > 0; + } + + private static int MINUS(boolean a, boolean b) { + int aa = a ? 1 : 0; + int bb = b ? 1 : 0; + return aa - bb; + } + + public static LogicConstantNode asLogicConstantNode(LogicNode cond) { + return (cond instanceof LogicConstantNode) ? (LogicConstantNode) cond : null; + } + + public static boolean isLiteralNode(ValueNode f) { + return f instanceof ConstantNode || f instanceof LogicConstantNode; + } + + public static boolean isConstantTrue(LogicNode cond) { + LogicConstantNode c = asLogicConstantNode(cond); + return (c != null) && c.getValue(); + } + + public static boolean isConstantFalse(LogicNode cond) { + LogicConstantNode c = asLogicConstantNode(cond); + return (c != null) && !c.getValue(); + } + + public static boolean alwaysFails(boolean isNegated, LogicNode cond) { + LogicConstantNode c = asLogicConstantNode(cond); + return (c != null) && (c.getValue() == isNegated); + } + + public static boolean alwaysSucceeds(boolean isNegated, LogicNode cond) { + LogicConstantNode c = asLogicConstantNode(cond); + return (c != null) && (c.getValue() != isNegated); + } + + /** + * Returns (preserving order) the ValueNodes without duplicates found among the argument's + * direct inputs. + */ + @SuppressWarnings("unchecked") + public static List<ValueNode> distinctValueAndConditionInputs(Node n) { + ArrayList<ValueNode> result = null; + NodeClass.NodeClassIterator iter = n.inputs().iterator(); + while (iter.hasNext()) { + NodeClass.Position pos = iter.nextPosition(); + InputType inputType = pos.getInputType(n); + boolean isReducibleInput = (inputType == InputType.Value || inputType == InputType.Condition); + if (isReducibleInput) { + ValueNode i = (ValueNode) pos.get(n); + if (!isLiteralNode(i)) { + if (result == null) { + result = new ArrayList<>(); + } + if (!result.contains(i)) { + result.add(i); + } + } + } + } + return result == null ? Collections.EMPTY_LIST : result; + } + + public static ObjectStamp asNonNullStamp(ObjectStamp stamp) { + ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.objectNonNull()); + assert result.isLegal(); + return result; + } + + public static ObjectStamp asRefinedStamp(ObjectStamp stamp, ResolvedJavaType joinType) { + assert !joinType.isInterface(); + ObjectStamp result = (ObjectStamp) stamp.join(StampFactory.declared(joinType)); + assert result.isLegal(); + return result; + } + + /** + * Start situation: the parent node has <code>oldInput</code> among its (direct) inputs. After + * this method has run, all such occurrences have been replaced with <code>newInput</code>. In + * case that makes <code>oldInput</code> disconnected, it is removed from the graph. + */ + public static void replaceInPlace(Node parent, Node oldInput, Node newInput) { + assert parent != null; + assert parent.inputs().contains(oldInput); + if (oldInput == newInput) { + return; + } + assert oldInput != null && newInput != null; + assert !isLiteralNode((ValueNode) oldInput); + do { + parent.replaceFirstInput(oldInput, newInput); + } while (parent.inputs().contains(oldInput)); + // `oldInput` if unused wil be removed in finished() + } + + public static StructuredGraph visualize(StructuredGraph graph, String title) { + DebugConfig debugConfig = DebugScope.getConfig(); + DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output()); + try (DebugConfigScope s = Debug.setConfig(fixedConfig)) { + Debug.dump(graph, title); + + return graph; + } + } + + public static final String ANSI_RESET = "\u001B[0m"; + public static final String ANSI_BLACK = "\u001B[30m"; + public static final String ANSI_RED = "\u001B[31m"; + public static final String ANSI_GREEN = "\u001B[32m"; + public static final String ANSI_YELLOW = "\u001B[33m"; + public static final String ANSI_BLUE = "\u001B[34m"; + public static final String ANSI_PURPLE = "\u001B[35m"; + public static final String ANSI_CYAN = "\u001B[36m"; + public static final String ANSI_WHITE = "\u001B[37m"; + + public static void highlightInRed(String msg) { + System.out.println(ANSI_RED + msg + ANSI_RESET); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,373 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.Debug; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.IsNullNode; +import com.oracle.graal.nodes.extended.GuardingNode; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.compiler.common.type.ObjectStamp; +import com.oracle.graal.nodes.type.StampTool; +import com.oracle.graal.phases.tiers.PhaseContext; + +/** + * <p> + * This class implements control-flow sensitive reductions for + * {@link com.oracle.graal.nodes.GuardingPiNode}. + * </p> + * + * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode) + */ +public abstract class GuardingPiReduction extends BaseReduction { + + public GuardingPiReduction(FixedNode start, State initialState, PhaseContext context) { + super(start, initialState, context); + } + + /** + * <p> + * By the time a {@link com.oracle.graal.nodes.GuardingPiNode GuardingPiNode} is visited, the + * available type refinements may allow reductions similar to those performed for + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode) + * CheckCastNode}. + * </p> + * + * <ol> + * <li> + * If the condition needs no reduction (ie, it's already a + * {@link com.oracle.graal.nodes.LogicConstantNode LogicConstantNode}), this method basically + * gives up (thus letting other phases take care of it).</li> + * <li> + * Otherwise, an attempt is made to find a {@link com.oracle.graal.nodes.extended.GuardingNode} + * that implies the combination of (negated, condition) of the + * {@link com.oracle.graal.nodes.GuardingPiNode} being visited. Details in + * {@link #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}. If found, the node + * can be removed.</li> + * <li> + * Otherwise, the node is lowered to a {@link com.oracle.graal.nodes.FixedGuardNode} and its + * usages replaced with {@link com.oracle.graal.nodes.PiNode}. Details in + * {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}.</li> + * </ol> + * + * <p> + * Precondition: the condition hasn't been deverbosified yet. + * </p> + * + */ + protected final void visitGuardingPiNode(GuardingPiNode envelope) { + + if (!FlowUtil.hasLegalObjectStamp(envelope)) { + // this situation exercised by com.oracle.graal.jtt.optimize.NCE_FlowSensitive02 + return; + } + if (!FlowUtil.hasLegalObjectStamp(envelope.object())) { + return; + } + + /* + * (1 of 3) Cover the case of GuardingPiNode(LogicConstantNode, ...) + */ + + if (envelope.condition() instanceof LogicConstantNode) { + if (FlowUtil.alwaysFails(envelope.isNegated(), envelope.condition())) { + state.impossiblePath(); + // let GuardingPiNode(false).canonical() prune the dead-code control-path + return; + } + // if not always-fails and condition-constant, then it always-succeeds! + assert FlowUtil.alwaysSucceeds(envelope.isNegated(), envelope.condition()); + // let GuardingPiNode(true).canonical() replaceAtUsages + return; + } + + /* + * The trick used in visitFixedGuardNode to look up an equivalent GuardingNode for the + * combination of (negated, condition) at hand doesn't work for GuardingPiNode, because the + * condition showing up here (a ShortCircuitOrNode that can be detected by + * CastCheckExtractor) doesn't appear as key in trueFacts, falseFacts. Good thing we have + * CastCheckExtractor! + */ + + /* + * (2 of 3) Cover the case of the condition known-to-be-false or known-to-be-true, but not + * LogicConstantNode. + * + * If deverbosify(condition) == falseConstant, it would be safe to set: + * `envelope.setCondition(falseConstant)` (only the API won't allow). + * + * On the other hand, it's totally unsafe to do something like that for trueConstant. What + * we can do about that case is the province of `tryRemoveGuardingPiNode(envelope)` + */ + + if (tryRemoveGuardingPiNode(envelope)) { + return; + } + + /* + * Experience has shown that an attempt to eliminate the current GuardingPiNode by using a + * GuardingNode already in scope and with equivalent condition (grabbed from `trueFacts` + * resp. `falseFacts`) proves futile. Therefore we're not even attempting that here. + */ + + /* + * (3 of 3) Neither always-succeeds nor always-fails, ie we don't known. Converting to + * FixedGuardNode allows tracking the condition via a GuardingNode, thus potentially + * triggering simplifications down the road. + */ + FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(envelope.condition(), envelope.getReason(), envelope.getAction(), envelope.isNegated())); + graph.addBeforeFixed(envelope, fixedGuard); + + if (!FlowUtil.lacksUsages(envelope)) { + // not calling wrapInPiNode() because we don't want to rememberSubstitution() + PiNode replacement = graph.unique(new PiNode(envelope.object(), envelope.stamp(), fixedGuard)); + reasoner.added.add(replacement); + // before removing the GuardingPiNode replace its usages + envelope.replaceAtUsages(replacement); + } + + graph.removeFixed(envelope); + + state.addFact(!fixedGuard.isNegated(), fixedGuard.condition(), fixedGuard); + + } + + /** + * <p> + * Based on flow-sensitive knowledge, two pre-requisites have to be fulfilled in order to remove + * a {@link com.oracle.graal.nodes.GuardingPiNode}: + * + * <ul> + * <li>the condition must refer only to the payload of the + * {@link com.oracle.graal.nodes.GuardingPiNode}</li> + * <li>the condition must check properties about which the state tracks not only a true/false + * answer, but also an anchor witnessing that fact</li> + * <li>the condition may not check anything else beyond what's stated in the items above.</li> + * </ul> + * </p> + * + * <p> + * Provided a condition as above can be reduced to a constant (and an anchor obtained in the + * process), this method replaces all usages of the + * {@link com.oracle.graal.nodes.GuardingPiNode} (necessarily of + * {@link com.oracle.graal.graph.InputType#Value}) with a {@link com.oracle.graal.nodes.PiNode} + * that wraps the payload and the anchor in question. + * </p> + * + * <p> + * Precondition: the condition hasn't been deverbosified yet. + * </p> + * + * @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode) + * + */ + private boolean tryRemoveGuardingPiNode(GuardingPiNode envelope) { + + LogicNode cond = envelope.condition(); + ValueNode payload = envelope.object(); + + ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp(); + ObjectStamp payloadStamp = (ObjectStamp) payload.stamp(); + + if (isNullCheckOn(cond, payload)) { + if (envelope.isNegated()) { + /* + * GuardingPiNode succeeds if payload non-null + */ + if (!outgoingStamp.equals(FlowUtil.asNonNullStamp(payloadStamp))) { + warnAboutOutOfTheBlueGuardingPiNode(envelope); + } + return tryRemoveGuardingPiNodeNonNullCond(envelope); + } else { + /* + * GuardingPiNode succeeds if payload null + */ + ValueNode replacement = StampTool.isObjectAlwaysNull(payload) ? payload : reasoner.nonTrivialNull(payload); + if (replacement != null) { + // replacement == null means !isKnownNull(payload) + removeGuardingPiNode(envelope, replacement); + return true; + } + return false; + } + } else if (CastCheckExtractor.isInstanceOfCheckOn(cond, payload)) { + if (envelope.isNegated()) { + return false; + } + /* + * GuardingPiNode succeeds if payload instanceof <something> + */ + InstanceOfNode io = (InstanceOfNode) cond; + assert io.type() != null; + Witness w = state.typeInfo(payload); + if (w != null && w.isNonNull() && isEqualOrMorePrecise(w.type(), io.type())) { + ValueNode d = reasoner.downcast(payload); + removeGuardingPiNode(envelope, d); + return true; + } + return false; + } else if (cond instanceof ShortCircuitOrNode) { + if (envelope.isNegated()) { + return false; + } + CastCheckExtractor cce = CastCheckExtractor.extract(cond); + if (cce == null || cce.subject != payload) { + return false; + } + /* + * GuardingPiNode succeeds if payload check-casts toType + */ + return tryRemoveGuardingPiNodeCheckCastCond(envelope, cce.type); + } + + return false; + } + + /** + * Porcelain method. + * + * This method handles the case where the GuardingPiNode succeeds if payload known to be + * non-null. + * + * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode) + */ + private boolean tryRemoveGuardingPiNodeNonNullCond(GuardingPiNode envelope) { + + ValueNode payload = envelope.object(); + + if (state.isNull(payload)) { + // the GuardingPiNode fails always + postponedDeopts.addDeoptBefore(envelope, envelope.getReason()); + state.impossiblePath(); + return true; + } + + if (StampTool.isObjectNonNull(payload)) { + // payload needs no downcasting, it satisfies as-is the GuardingPiNode's condition. + if (precisionLoss(envelope, payload)) { + /* + * TODO The GuardingPiNode has an outgoing stamp whose narrowing goes beyond what + * the condition checks. That's suspicious. + */ + PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp())); + reasoner.added.add(replacement); + removeGuardingPiNode(envelope, replacement); + return true; + } else { + removeGuardingPiNode(envelope, payload); + return true; + } + } + // if a non-null witness available, the GuardingPiNode can be removed + + Witness w = state.typeInfo(payload); + GuardingNode nonNullAnchor = (w != null && w.isNonNull()) ? w.guard() : null; + if (nonNullAnchor != null) { + PiNode replacement = graph.unique(new PiNode(payload, envelope.stamp(), nonNullAnchor.asNode())); + reasoner.added.add(replacement); + removeGuardingPiNode(envelope, replacement); + return true; + } + + /* + * TODO What about, nodes that always denote non-null values? (Even though their stamp + * forgot to make that clear) Candidates: ObjectGetClassNode, Parameter(0) on instance + */ + + return false; + } + + /** + * Porcelain method. + * + * This method handles the case where the GuardingPiNode succeeds if payload null or its actual + * type equal or subtype of `toType` + * + * @see #tryRemoveGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode) + * + */ + private boolean tryRemoveGuardingPiNodeCheckCastCond(GuardingPiNode envelope, ResolvedJavaType toType) { + assert toType != null; + ValueNode payload = envelope.object(); + + ObjectStamp outgoingStamp = (ObjectStamp) envelope.stamp(); + ObjectStamp payloadStamp = (ObjectStamp) payload.stamp(); + + if (!outgoingStamp.equals(FlowUtil.asRefinedStamp(payloadStamp, toType))) { + warnAboutOutOfTheBlueGuardingPiNode(envelope); + } + + ValueNode d = reasoner.downcast(payload); + if (d == null) { + return false; + } + + if (StampTool.isObjectAlwaysNull(d)) { + removeGuardingPiNode(envelope, d); + return true; + } + ObjectStamp dStamp = (ObjectStamp) d.stamp(); + if (isEqualOrMorePrecise(dStamp.type(), toType)) { + removeGuardingPiNode(envelope, d); + return true; + } + return false; + } + + /* + * TODO There should be an assert in GuardingPiNode to detect that as soon as it happens + * (constructor, setStamp). + */ + private static void warnAboutOutOfTheBlueGuardingPiNode(GuardingPiNode envelope) { + Debug.log(String.format("GuardingPiNode has an outgoing stamp whose narrowing goes beyond what its condition checks: %s", envelope)); + } + + private static boolean isNullCheckOn(LogicNode cond, ValueNode subject) { + if (!(cond instanceof IsNullNode)) { + return false; + } + IsNullNode isNull = (IsNullNode) cond; + return isNull.object() == subject; + } + + /** + * Porcelain method. + */ + private void removeGuardingPiNode(GuardingPiNode envelope, ValueNode replacement) { + assert !precisionLoss(envelope, replacement); + metricGuardingPiNodeRemoved.increment(); + envelope.replaceAtUsages(replacement); + assert FlowUtil.lacksUsages(envelope); + graph.removeFixed(envelope); + } + + public static boolean isEqualOrMorePrecise(ResolvedJavaType a, ResolvedJavaType b) { + return a.equals(b) || FlowUtil.isMorePrecise(a, b); + } + + public static boolean isEqualOrMorePrecise(ObjectStamp a, ObjectStamp b) { + return a.equals(b) || FlowUtil.isMorePrecise(a, b); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,70 @@ +/* + * 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.phases.common.cfs; + +import java.util.Map; +import java.util.TreeMap; + +public class Histogram extends TreeMap<Integer, Integer> { + + private static final long serialVersionUID = 7188324319057387738L; + + private final String prefix; + + public Histogram(String prefix) { + this.prefix = prefix; + } + + public void tick(int bucket) { + Integer entry = get(bucket); + put(bucket, entry == null ? 1 : entry + 1); + } + + public void print() { + + // printing takes time, allow concurrent updates during printing + Histogram histogram = clone(); + + float casesTotal = 0; + for (int i : histogram.values()) { + casesTotal += i; + } + for (Map.Entry<Integer, Integer> entry : histogram.entrySet()) { + int numCases = entry.getValue(); + int percentOut = (int) (numCases / casesTotal * 100); + String msg = prefix + String.format("%d iters in %4d cases (%2d %%)", entry.getKey(), numCases, percentOut); + if (entry.getKey() > 3) { + FlowUtil.highlightInRed(msg); + } else { + System.out.println(msg); + } + } + System.out.println(prefix + "--------------------------"); + } + + @Override + public Histogram clone() { + return (Histogram) super.clone(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/IterativeFlowSensitiveReductionPhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,90 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.CanonicalizerPhase; +import com.oracle.graal.phases.common.util.*; +import com.oracle.graal.phases.tiers.*; + +public class IterativeFlowSensitiveReductionPhase extends BasePhase<PhaseContext> { + + private static final int MAX_ITERATIONS = 256; + + private final CanonicalizerPhase canonicalizer; + + public IterativeFlowSensitiveReductionPhase(CanonicalizerPhase canonicalizer) { + this.canonicalizer = canonicalizer; + } + + public static class CountingListener extends HashSetNodeChangeListener { + + public int count; + + @Override + public void nodeChanged(Node node) { + super.nodeChanged(node); + } + + } + + // private Histogram histogram = new Histogram("FSR-"); + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + FlowSensitiveReductionPhase eliminate = new FlowSensitiveReductionPhase(context.getMetaAccess()); + CountingListener listener = new CountingListener(); + int count = 1; + while (true) { + listener.count = count; + graph.trackInputChange(listener); + graph.trackUsagesDroppedZero(listener); + eliminate.apply(graph, context); + graph.stopTrackingInputChange(); + graph.stopTrackingUsagesDroppedZero(); + if (listener.getChangedNodes().isEmpty()) { + // histogram.tick(count); + break; + } + for (Node node : graph.getNodes()) { + if (node instanceof Simplifiable) { + listener.getChangedNodes().add(node); + } + } + canonicalizer.applyIncremental(graph, context, listener.getChangedNodes()); + listener.getChangedNodes().clear(); + if (++count > MAX_ITERATIONS) { + // System.out.println("Bailing out IterativeFlowSensitiveReductionPhase for graph: " + // + graph); + // FlowUtil.visualize(graph, "Bailout"); + throw new BailoutException("Number of iterations in FlowSensitiveReductionPhase exceeds " + MAX_ITERATIONS); + } + } + // histogram.print(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,824 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.Kind; +import com.oracle.graal.api.meta.ResolvedJavaType; +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugMetric; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.IsNullNode; +import com.oracle.graal.nodes.calc.ObjectEqualsNode; +import com.oracle.graal.nodes.extended.GuardedNode; +import com.oracle.graal.nodes.extended.GuardingNode; +import com.oracle.graal.nodes.java.InstanceOfNode; +import com.oracle.graal.nodes.spi.ValueProxy; +import com.oracle.graal.compiler.common.type.ObjectStamp; +import com.oracle.graal.nodes.type.StampTool; +import com.oracle.graal.nodes.util.GraphUtil; +import com.oracle.graal.phases.graph.MergeableState; + +import java.lang.reflect.Modifier; +import java.util.*; + +/** + * A State instance is mutated in place as each FixedNode is visited in a basic block of + * instructions. Basic block: starts with a {@link com.oracle.graal.nodes.BeginNode BeginNode}, ends + * at an {@link com.oracle.graal.nodes.EndNode EndNode} or + * {@link com.oracle.graal.nodes.ControlSinkNode ControlSinkNode} and lacks intervening control + * splits or merges. + */ +public final class State extends MergeableState<State> implements Cloneable { + + private static final DebugMetric metricTypeRegistered = Debug.metric("TypeRegistered"); + private static final DebugMetric metricNullnessRegistered = Debug.metric("NullnessRegistered"); + private static final DebugMetric metricObjectEqualsRegistered = Debug.metric("ObjectEqualsRegistered"); + private static final DebugMetric metricImpossiblePathDetected = Debug.metric("ImpossiblePathDetected"); + + /** + * <p> + * Each state update results in a higher {@link State#versionNr versionNr}. The + * {@link State#versionNr versionNr} of different State instances can't be meaningfully compared + * (ie, same {@link State#versionNr versionNr} just indicates they've gone through the same + * number of updates). In particular, the {@link State#versionNr versionNr} of a merged state + * doesn't guarantee any more than being different from those of the states being merged. + * </p> + * + * <p> + * Still, {@link State#versionNr versionNr} proves useful in two cases: + * + * <ul> + * <li>recording the {@link State#versionNr versionNr} right after {@link State State} cloning, + * allows finding out afterwards whether (a) both states have diverged, (b) just one of them, or + * (c) none of them.</li> + * <li>a {@link State State} may become {@link State#isUnreachable isUnreachable}. In such case, + * it may make a difference whether any updates were performed on the state from the time it was + * cloned. Those updates indicate information not available in the state is was cloned from. For + * the purposes of {@link FlowSensitiveReduction FlowSensitiveReduction} an unreachable state + * need not be merged with any other (because control-flow won't reach the merge point over the + * path of the unreachable state).</li> + * </ul> + * </p> + * + */ + int versionNr = 0; + + boolean isUnreachable = false; + + /** + * Getting here implies an opportunity was detected for dead-code-elimination. A counterpoint + * argument goes as follows: perhaps we don't get here that often, in which case the effort to + * detect an "impossible path" could be shaved off. + * + * @see com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt + */ + void impossiblePath() { + isUnreachable = true; + metricImpossiblePathDetected.increment(); + } + + /** + * <p> + * This map semantically tracks "facts" (ie, properties valid for the program-point the state + * refers to) as opposed to floating-guard-dependent properties. The + * {@link com.oracle.graal.nodes.extended.GuardingNode} being tracked comes handy at + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction#visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)} + * . + * </p> + * + * <p> + * On a related note, {@link #typeRefinements} also captures information the way + * {@link #trueFacts} and {@link #falseFacts} do, including "witnessing" guards. Why not just + * standardize on one of them, and drop the other? Because the {@link #typeRefinements} eagerly + * aggregates information for easier querying afterwards, e.g. when producing a "downcasted" + * value (which involves building a {@link com.oracle.graal.nodes.PiNode}, see + * {@link EquationalReasoner#downcast(com.oracle.graal.nodes.ValueNode) downcast()} + * </p> + * + */ + private IdentityHashMap<ValueNode, Witness> typeRefinements; + + IdentityHashMap<ValueNode, GuardingNode> knownNull; + IdentityHashMap<LogicNode, GuardingNode> trueFacts; + IdentityHashMap<LogicNode, GuardingNode> falseFacts; + + public State() { + this.typeRefinements = new IdentityHashMap<>(); + this.knownNull = new IdentityHashMap<>(); + this.trueFacts = new IdentityHashMap<>(); + this.falseFacts = new IdentityHashMap<>(); + } + + public State(State other) { + this.isUnreachable = other.isUnreachable; + this.versionNr = other.versionNr; + this.typeRefinements = new IdentityHashMap<>(); + for (Map.Entry<ValueNode, Witness> entry : other.typeRefinements.entrySet()) { + this.typeRefinements.put(entry.getKey(), new Witness(entry.getValue())); + } + this.knownNull = new IdentityHashMap<>(other.knownNull); + this.trueFacts = new IdentityHashMap<>(other.trueFacts); + this.falseFacts = new IdentityHashMap<>(other.falseFacts); + } + + /** + * @return A new list containing only those states that are reachable. + */ + private static ArrayList<State> reachableStates(List<State> states) { + ArrayList<State> result = new ArrayList<>(states); + Iterator<State> iter = result.iterator(); + while (iter.hasNext()) { + if (iter.next().isUnreachable) { + iter.remove(); + } + } + return result; + } + + private IdentityHashMap<ValueNode, Witness> mergeKnownTypes(MergeNode merge, ArrayList<State> withReachableStates) { + IdentityHashMap<ValueNode, Witness> newKnownTypes = new IdentityHashMap<>(); + + for (Map.Entry<ValueNode, Witness> entry : typeRefinements.entrySet()) { + ValueNode node = entry.getKey(); + Witness type = new Witness(entry.getValue()); + + for (State other : withReachableStates) { + Witness otherType = other.typeInfo(node); + if (otherType == null) { + type = null; + break; + } + type.merge(otherType, merge); + } + if (type != null && type.knowsBetterThan(node)) { + assert node == GraphUtil.unproxify(node); + newKnownTypes.put(node, type); + } + } + + return newKnownTypes; + } + + private IdentityHashMap<ValueNode, GuardingNode> mergeKnownNull(MergeNode merge, ArrayList<State> withReachableStates) { + // newKnownNull starts empty + IdentityHashMap<ValueNode, GuardingNode> newKnownNull = new IdentityHashMap<>(); + for (Map.Entry<ValueNode, GuardingNode> entry : knownNull.entrySet()) { + ValueNode key = entry.getKey(); + GuardingNode newGN = entry.getValue(); + boolean missing = false; + + for (State other : withReachableStates) { + GuardingNode otherGuard = other.knownNull.get(key); + if (otherGuard == null) { + missing = true; + break; + } + if (otherGuard != newGN) { + newGN = merge; + } + } + if (!missing) { + newKnownNull.put(key, newGN); + } + } + return newKnownNull; + } + + /** + * <p> + * This method handles phis, by adding to the resulting state any information that can be gained + * (about type-refinement and nullness) based on the data available at each of the incoming + * branches. + * </p> + * + * <p> + * In more detail, <code>FlowSensitiveReduction#visitAbstractEndNode()</code> has already + * deverbosified the phi-values contributed by each reachable branch. The paths that + * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction} determined to be + * unreachable will be eliminated by canonicalization and dead code elimination. For now they + * still exist, thus polluting the result of + * {@link com.oracle.graal.nodes.ValuePhiNode#inferPhiStamp()} but we are careful to skip them + * when merging type-witnesses and known-null maps. + * </p> + */ + private void mergePhis(MergeNode merge, List<State> withStates, IdentityHashMap<ValueNode, Witness> newKnownPhiTypes, IdentityHashMap<ValueNode, GuardingNode> newKnownNullPhis) { + + if (merge instanceof LoopBeginNode) { + return; + } + + for (PhiNode phi : merge.phis()) { + assert phi == GraphUtil.unproxify(phi); + if (phi instanceof ValuePhiNode && phi.getKind() == Kind.Object) { + ArrayList<ValueNode> reachingValues = new ArrayList<>(); + if (!isUnreachable) { + reachingValues.add(phi.valueAt(0)); + } + for (int i = 0; i < withStates.size(); i++) { + State otherState = withStates.get(i); + if (!otherState.isUnreachable) { + reachingValues.add(phi.valueAt(i + 1)); + } + } + assert !reachingValues.isEmpty(); + ObjectStamp phiStamp = (ObjectStamp) phi.stamp(); + ObjectStamp nonPollutedStamp = (ObjectStamp) StampTool.meet(reachingValues); + Witness w = new Witness(nonPollutedStamp, merge); + if (FlowUtil.isMorePrecise(w.type(), phiStamp.type())) { + // precision gain regarding type + newKnownPhiTypes.put(phi, w); + // confirm no precision loss regarding nullness + assert implies(phiStamp.nonNull(), w.isNonNull()); + } else if (w.isNonNull() && !phiStamp.nonNull()) { + // precision gain regarding nullness + newKnownPhiTypes.put(phi, w); + // confirm no precision loss regarding type + assert !FlowUtil.isMorePrecise(phiStamp.type(), w.type()); + } + if (nonPollutedStamp.alwaysNull()) { + newKnownNullPhis.put(phi, merge); + } + } + } + + } + + private static boolean implies(boolean a, boolean b) { + return !a || b; + } + + @Override + public boolean merge(MergeNode merge, List<State> withStates) { + + ArrayList<State> withReachableStates = reachableStates(withStates); + if (withReachableStates.isEmpty()) { + return true; + } + + for (State state : withReachableStates) { + versionNr = Math.max(versionNr, state.versionNr) + 1; + isUnreachable &= state.isUnreachable; + } + + if (isUnreachable) { + typeRefinements.clear(); + knownNull.clear(); + trueFacts.clear(); + falseFacts.clear(); + return true; + } + + // may also get updated in a moment, during processing of phi nodes. + IdentityHashMap<ValueNode, Witness> newKnownTypes = mergeKnownTypes(merge, withReachableStates); + // may also get updated in a moment, during processing of phi nodes. + IdentityHashMap<ValueNode, GuardingNode> newKnownNull = mergeKnownNull(merge, withReachableStates); + mergePhis(merge, withStates, newKnownTypes, newKnownNull); + this.typeRefinements = newKnownTypes; + this.knownNull = newKnownNull; + + this.trueFacts = mergeTrueFacts(withReachableStates, merge); + this.falseFacts = mergeFalseFacts(withReachableStates, merge); + return true; + } + + private IdentityHashMap<LogicNode, GuardingNode> mergeTrueFacts(ArrayList<State> withReachableStates, GuardingNode merge) { + IdentityHashMap<LogicNode, GuardingNode> newTrueConditions = new IdentityHashMap<>(); + for (Map.Entry<LogicNode, GuardingNode> entry : trueFacts.entrySet()) { + LogicNode check = entry.getKey(); + GuardingNode guard = entry.getValue(); + + for (State other : withReachableStates) { + GuardingNode otherGuard = other.trueFacts.get(check); + if (otherGuard == null) { + guard = null; + break; + } + if (otherGuard != guard) { + guard = merge; + } + } + if (guard != null) { + newTrueConditions.put(check, guard); + } + } + return newTrueConditions; + } + + private IdentityHashMap<LogicNode, GuardingNode> mergeFalseFacts(ArrayList<State> withReachableStates, GuardingNode merge) { + IdentityHashMap<LogicNode, GuardingNode> newFalseConditions = new IdentityHashMap<>(); + for (Map.Entry<LogicNode, GuardingNode> entry : falseFacts.entrySet()) { + LogicNode check = entry.getKey(); + GuardingNode guard = entry.getValue(); + + for (State other : withReachableStates) { + GuardingNode otherGuard = other.falseFacts.get(check); + if (otherGuard == null) { + guard = null; + break; + } + if (otherGuard != guard) { + guard = merge; + } + } + if (guard != null) { + newFalseConditions.put(check, guard); + } + } + return newFalseConditions; + } + + /** + * @return null if no type-witness available for the argument, the witness otherwise. + */ + public Witness typeInfo(ValueNode object) { + assert FlowUtil.hasLegalObjectStamp(object); + return typeRefinements.get(GraphUtil.unproxify(object)); + } + + /** + * @return true iff the argument is known to stand for null. + */ + public boolean isNull(ValueNode object) { + assert FlowUtil.hasLegalObjectStamp(object); + return StampTool.isObjectAlwaysNull(object) || knownNull.containsKey(GraphUtil.unproxify(object)); + } + + /** + * <p> + * It makes a difference calling {@link Witness#isNonNull()} as opposed to + * {@link State#isNonNull(com.oracle.graal.nodes.ValueNode)}. The former guarantees the witness + * provides a guard certifying non-nullness. The latter just tells us there exists some guard + * that certifies the property we asked about. + * </p> + * + * <p> + * TODO improvement: isKnownNonNull could be made smarter by noticing some nodes always denote a + * non-null value (eg, ObjectGetClassNode). Similarly for isKnownNull. Code that looks at the + * stamp as well as code that looks for a non-null-witness would benefit from also checking such + * extended isKnownNonNull. Alternatively, the stamp of those nodes should always have + * is-non-null set. + * </p> + * + * @return true iff the argument is known to stand for non-null. + */ + public boolean isNonNull(ValueNode object) { + assert FlowUtil.hasLegalObjectStamp(object); + if (StampTool.isObjectNonNull(object)) { + return true; + } + Witness w = typeInfo(object); + return w == null ? false : w.isNonNull(); + } + + /** + * @return true iff the argument is known to stand for an object conforming to the given type. + */ + public boolean knownToConform(ValueNode object, ResolvedJavaType to) { + assert FlowUtil.hasLegalObjectStamp(object); + assert !to.isPrimitive(); + ResolvedJavaType stampType = StampTool.typeOrNull(object); + if (stampType != null && to.isAssignableFrom(stampType)) { + return true; + } + final ValueNode scrutinee = GraphUtil.unproxify(object); + if (isNull(scrutinee)) { + return true; + } + Witness w = typeInfo(scrutinee); + boolean witnessAnswer = w != null && w.type() != null && to.isAssignableFrom(w.type()); + if (witnessAnswer) { + return true; + } + return false; + } + + /** + * @return true iff the argument is known to stand for an object that definitely does not + * conform to the given type. + */ + public boolean knownNotToConform(ValueNode object, ResolvedJavaType to) { + assert FlowUtil.hasLegalObjectStamp(object); + assert !to.isPrimitive(); + final ValueNode scrutinee = GraphUtil.unproxify(object); + if (isNull(scrutinee)) { + return false; + } + ResolvedJavaType stampType = StampTool.typeOrNull(object); + if (stampType != null && knownNotToConform(stampType, to)) { + return true; + } + Witness w = typeInfo(scrutinee); + boolean witnessAnswer = w != null && !w.cluelessAboutType() && knownNotToConform(w.type(), to); + if (witnessAnswer) { + return true; + } + return false; + } + + // @formatter:off + /** + * \ | | | | + * \ b| | | | + * a \ | | | | + * \|iface|final|non-f| + * -----+-----------------| + * iface| F | F | F | + * -----+-----------------| + * final| C | C | C | + * -----+-----------------| + * non-f| F | C | C | + * -----------------------+ + * + * where: + * F: false + * C: check + * iface: interface + * final: exact non-interface reference-type + * non-f: non-exact non-interface reference-type + * + * @return true iff the first argument is known not to conform to the second argument. + */ + // @formatter:on + public static boolean knownNotToConform(ResolvedJavaType a, ResolvedJavaType b) { + assert !a.isPrimitive(); + assert !b.isPrimitive(); + if (b.isAssignableFrom(a)) { + return false; + } + if (a.isInterface()) { + return false; + } + boolean aFinal = Modifier.isFinal(a.getModifiers()); + if (b.isInterface() && !aFinal) { + return false; + } + if (a.isAssignableFrom(b)) { + return false; + } else { + return true; + } + } + + @Override + public State clone() { + return new State(this); + } + + /** + * Porcelain method. + */ + private Witness getOrElseAddTypeInfo(ValueNode object) { + ValueNode scrutinee = GraphUtil.unproxify(object); + Witness w = typeRefinements.get(scrutinee); + if (w == null) { + w = new Witness(); + typeRefinements.put(scrutinee, w); + } + return w; + } + + /** + * <p> + * Updates this {@link State State} to account for an observation about the scrutinee being + * non-null. In case instanceof was observed, + * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode) + * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead. + * </p> + * + * <p> + * No check is made on whether a contradiction would be introduced into the factbase (in which + * case the state should be marked unreachable), the caller takes care of that. + * </p> + * + * @return whether state was updated (iff the observation added any new information) + */ + public boolean trackNN(ValueNode object, GuardingNode anchor) { + if (isDependencyTainted(object, anchor)) { + return false; + } + assert anchor instanceof FixedNode; + ResolvedJavaType stampType = StampTool.typeOrNull(object); + if (stampType != null && !stampType.isInterface()) { + return trackIO(object, stampType, anchor); + } + Witness w = getOrElseAddTypeInfo(object); + if (w.trackNN(anchor)) { + versionNr++; + return true; + } + return false; + } + + /** + * Updates this {@link State State} to account for an observation about the scrutinee conforming + * to a type. In case instanceof was observed, + * {@link #trackIO(com.oracle.graal.nodes.ValueNode, com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode) + * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead. + * + * <p> + * No check is made on whether a contradiction would be introduced into the factbase (in which + * case the state should be marked unreachable), the caller must take care of that. + * </p> + * + * @return false iff the observed type is an interface, or doesn't provide any new information + * not already known. Ie, this method returns true iff the observation resulted in + * information gain. + */ + public boolean trackCC(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) { + if (observed.isInterface()) { + return false; + } + if (isDependencyTainted(object, anchor)) { + return false; + } + assert anchor instanceof FixedNode; + Witness w = getOrElseAddTypeInfo(object); + if (w.trackCC(observed, anchor)) { + versionNr++; + metricTypeRegistered.increment(); + return true; + } + return false; + } + + /** + * Updates this {@link State State} to account for an observation about the non-null scrutinee + * conforming to a type. + * + * <p> + * No check is made on whether a contradiction would be introduced into the factbase (in which + * case the state should be marked unreachable), the caller must take care of that. + * </p> + * + * @return whether state was updated (iff the observation added any new information) + */ + public boolean trackIO(ValueNode object, ResolvedJavaType observed, GuardingNode anchor) { + assert !observed.isInterface() : "no infrastructure yet in State.Witness to support interfaces in general"; + if (isDependencyTainted(object, anchor)) { + return false; + } + assert anchor instanceof FixedNode; + Witness w = getOrElseAddTypeInfo(object); + if (w.trackIO(observed, anchor)) { + versionNr++; + metricTypeRegistered.increment(); + return true; + } + return false; + } + + /** + * This method increases {@link #versionNr} (thus potentially invalidating + * {@link EquationalReasoner EquationalReasoner}'s caches) only if the fact wasn't known + * already. + * + * <p> + * No check is made on whether a contradiction would be introduced into the factbase (in which + * case the state should be marked unreachable), the caller must take care of that. + * </p> + * + */ + private void addFactPrimordial(LogicNode condition, IdentityHashMap<LogicNode, GuardingNode> to, GuardingNode anchor) { + assert condition != null; + if (!to.containsKey(condition)) { + versionNr++; + to.put(condition, anchor); + } + } + + /** + * Ideas for the future: + * <ul> + * <li>track inferred less-than edges from (accumulated) CompareNode-s</li> + * <li>track set-representative for equality classes determined by (chained) IntegerTestNode</li> + * </ul> + * + */ + public void addFact(boolean isTrue, LogicNode condition, GuardingNode anchor) { + assert anchor != null; + assert anchor instanceof FixedNode; + assert !isUnreachable; + + if (condition instanceof LogicConstantNode) { + if (((LogicConstantNode) condition).getValue() != isTrue) { + impossiblePath(); + } + return; + } + + if (condition instanceof LogicNegationNode) { + addFact(!isTrue, ((LogicNegationNode) condition).getInput(), anchor); + } else if (condition instanceof ShortCircuitOrNode) { + /* + * We can register the conditions being or-ed as long as the anchor is a fixed node, + * because floating guards will be registered at a BeginNode but might be "valid" only + * later due to data flow dependencies. Therefore, registering both conditions of a + * ShortCircuitOrNode for a floating guard could lead to cycles in data flow, because + * the guard will be used as anchor for both conditions, and one condition could be + * depending on the other. + */ + if (isTrue) { + CastCheckExtractor cce = CastCheckExtractor.extract(condition); + if (cce == null || isDependencyTainted(cce.subject, anchor)) { + addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor); + } else { + trackCC(cce.subject, cce.type, anchor); + } + } else { + ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition; + addFact(disjunction.isXNegated(), disjunction.getX(), anchor); + // previous addFact might have resulted in impossiblePath() + if (isUnreachable) { + return; + } + addFact(disjunction.isYNegated(), disjunction.getY(), anchor); + } + } else if (condition instanceof InstanceOfNode) { + addFactInstanceOf(isTrue, (InstanceOfNode) condition, anchor); + } else if (condition instanceof IsNullNode) { + IsNullNode nullCheck = (IsNullNode) condition; + addNullness(isTrue, nullCheck.object(), anchor); + } else if (condition instanceof ObjectEqualsNode) { + addFactObjectEqualsNode(isTrue, (ObjectEqualsNode) condition, anchor); + } else { + addFactPrimordial(condition, isTrue ? trueFacts : falseFacts, anchor); + } + } + + /** + * An instanceof hint is tracked differently depending on whether it's an interface-test or not + * (because type-refinements currently lacks the ability to track interface types). + * + */ + private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) { + ValueNode object = instanceOf.object(); + if (isTrue) { + if (knownNotToConform(object, instanceOf.type())) { + impossiblePath(); + return; + } + addNullness(false, object, anchor); + if (instanceOf.type().isInterface()) { + if (!knownToConform(object, instanceOf.type())) { + addFactPrimordial(instanceOf, trueFacts, anchor); + } + } else { + trackIO(object, instanceOf.type(), anchor); + } + } else { + if (knownToConform(object, instanceOf.type())) { + impossiblePath(); // TODO this used to be a bug + return; + } + if (instanceOf.type().isInterface()) { + if (!knownNotToConform(object, instanceOf.type())) { + addFactPrimordial(instanceOf, falseFacts, anchor); + } + } + } + } + + private void addFactObjectEqualsNode(boolean isTrue, ObjectEqualsNode equals, GuardingNode anchor) { + if (isDependencyTainted(equals.x(), anchor)) { + return; + } + if (isDependencyTainted(equals.y(), anchor)) { + return; + } + assert anchor instanceof FixedNode; + ValueNode x = GraphUtil.unproxify(equals.x()); + ValueNode y = GraphUtil.unproxify(equals.y()); + if (isTrue) { + if (isNull(x) && isNonNull(y)) { + impossiblePath(); + return; + } + if (isNonNull(x) && isNull(y)) { + impossiblePath(); + return; + } + if (isNull(x) || isNull(y)) { + metricObjectEqualsRegistered.increment(); + addNullness(true, equals.x(), anchor); + addNullness(true, equals.y(), anchor); + } else if (isNonNull(x) || isNonNull(y)) { + metricObjectEqualsRegistered.increment(); + addNullness(false, equals.x(), anchor); + addNullness(false, equals.y(), anchor); + } + Witness wx = typeInfo(x); + Witness wy = typeInfo(y); + if (wx == null && wy == null) { + return; + } else if (wx != null && wy != null) { + // tighten their type-hints, provided at least one available + // both witnesses may have seen == null, ie they may be NN witnesses + ResolvedJavaType best = FlowUtil.tighten(wx.type(), wy.type()); + if (best != null) { + assert !best.isInterface(); + // type tightening is enough, nullness already taken care of + trackCC(equals.x(), best, anchor); + trackCC(equals.y(), best, anchor); + } + } else if (wx == null) { + typeRefinements.put(x, new Witness(wy)); + } else if (wy == null) { + typeRefinements.put(y, new Witness(wx)); + } + } else { + if (isNull(x) && !isNonNull(y)) { + metricObjectEqualsRegistered.increment(); + addNullness(false, equals.y(), anchor); + } else if (!isNonNull(x) && isNull(y)) { + metricObjectEqualsRegistered.increment(); + addNullness(false, equals.x(), anchor); + } + } + } + + /** + * Adds information about the nullness of a value. If isNull is true then the value is known to + * be null, otherwise the value is known to be non-null. + */ + public void addNullness(boolean isNull, ValueNode value, GuardingNode anchor) { + if (isDependencyTainted(value, anchor)) { + return; + } + assert anchor instanceof FixedNode; + ValueNode original = GraphUtil.unproxify(value); + boolean wasNull = isNull(original); + boolean wasNonNull = isNonNull(original); + if (isNull) { + if (wasNonNull) { + impossiblePath(); + } else { + metricNullnessRegistered.increment(); + versionNr++; + knownNull.put(original, anchor); + } + } else { + if (wasNull) { + impossiblePath(); + } else { + metricNullnessRegistered.increment(); + trackNN(original, anchor); + } + } + } + + /** + * + * @return true iff `value` may lose dependency not covered by `anchor`. + */ + public static boolean isDependencyTainted(ValueNode value, GuardingNode anchor) { + assert anchor instanceof FixedNode; + if (value instanceof ValueProxy) { + if (value instanceof GuardedNode) { + GuardedNode gn = (GuardedNode) value; + GuardingNode guardian = gn.getGuard(); + if (guardian != null) { + boolean isGuardedByFixed = guardian instanceof FixedNode; + if (!isGuardedByFixed) { + return true; + } + } + } + // if (value instanceof GuardingNode) { + // return true; + // } + ValueProxy proxy = (ValueProxy) value; + return isDependencyTainted(proxy.getOriginalNode(), anchor); + } + return false; + } + + public void clear() { + versionNr = 0; + isUnreachable = false; + typeRefinements.clear(); + knownNull.clear(); + trueFacts.clear(); + falseFacts.clear(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Witness.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,440 @@ +/* + * 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.phases.common.cfs; + +import com.oracle.graal.api.meta.ResolvedJavaType; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.GuardingNode; +import com.oracle.graal.compiler.common.type.ObjectStamp; + +/** + * <p> + * A witness progressively tracks more detailed properties about an object value (the scrutinee); + * the properties in question comprise whether the scrutinee has been observed: + * + * <ul> + * <li>as non-null,</li> + * <li>in a successful checkcast, or</li> + * <li>in a successful instanceof.</li> + * </ul> + * </p> + * + * <p> + * A witness is updated only when doing so increases the information content of the witness. For + * example, upon visiting a {@link com.oracle.graal.nodes.java.CheckCastNode CheckCastNode} the + * witness gets a chance to become updated. + * </p> + * + * <p> + * Therefore, at any given time, a witness represents the most detailed knowledge available so far + * about the scrutinee, which is the knowledge most relevant for upcoming program-points. + * </p> + * + * <p> + * The availability of witnesses about both non-nullness and checkcast (for a given scrutinee) + * promotes to an instanceof-style witness . The "levels" of knowledge a witness may exhibit are + * captured by {@link com.oracle.graal.phases.common.cfs.Witness.LEVEL}. For conciseness, the + * following query methods are available for a {@link com.oracle.graal.phases.common.cfs.Witness}: + * <ul> + * <li>{@link #atNonNull()}</li> + * <li>{@link #atCheckCast()}</li> + * <li>{@link #atInstanceOf()}</li> + * </ul> + * </p> + * + * <p> + * Only non-interface object types (ie, class and array types) are tracked. Small extensions are + * required to track interfaces, extensions that might be added after the current scheme proves + * itself. + * </p> + * + * <p> + * Some useful facts about the Statechart implemented by {@link Witness Witness}: + * + * <ul> + * <li>the start-state is "clueless"</li> + * <li> + * A self-transition via trackCC from whichever the current state is to itself, without information + * gain, is always possible. Just give {@link Object java.lang.Object} as observed type.</li> + * </ul> + * </p> + * + */ +public class Witness implements Cloneable { + + private static enum LEVEL { + CLUELESS, + NN, + CC, + IO + } + + private boolean atNonNull() { + return level == LEVEL.NN; + } + + private boolean atCheckCast() { + return level == LEVEL.CC; + } + + private boolean atInstanceOf() { + return level == LEVEL.IO; + } + + private void transition(LEVEL to, GuardingNode newAnchor) { + this.level = to; + this.gn = newAnchor; + assert repOK(); + } + + public Witness() { + } + + public Witness(Witness other) { + level = other.level; + seen = other.seen; + gn = other.gn; + } + + /** + * Counterpart to {@link #asStamp()} + */ + public Witness(ObjectStamp stamp, GuardingNode anchor) { + assert stamp.isLegal(); + assert anchor != null; + boolean isNonIface = (stamp.type() != null && !stamp.type().isInterface()); + if (stamp.nonNull()) { + if (isNonIface) { + seen = stamp.type(); + transition(LEVEL.IO, anchor); + } else { + seen = null; + transition(LEVEL.NN, anchor); + } + } else { + if (isNonIface) { + seen = stamp.type(); + transition(LEVEL.CC, anchor); + } else { + seen = null; + transition(LEVEL.CLUELESS, null); + assert clueless(); + } + } + assert repOK(); + } + + /** + * Type-witnesses aren't tracked for known-to-be-null. Therefore, although method + * {@link #isNonNull() isNonNull()} can be found in this class there's on purpose no companion + * <code>isNull()</code> . + */ + public boolean isNonNull() { + return atNonNull() || atInstanceOf(); + } + + /** + * The most precise type known so far about the scrutinee. (Please notice that nothing can be + * deduced about the non-nullness-status of the scrutinee from invoking this method alone). + */ + public ResolvedJavaType type() { + return seen; + } + + public ObjectStamp asStamp() { + boolean isKnownExact = (seen != null && seen.equals(seen.asExactType())); + return new ObjectStamp(seen, isKnownExact, isNonNull(), false); + } + + private LEVEL level = LEVEL.CLUELESS; + private ResolvedJavaType seen = null; + + /** + * Evidence (ie, a {@link com.oracle.graal.nodes.extended.GuardingNode}) attesting to the status + * reported by this witness. + * + * May be one of: + * + * <ul> + * <li> + * {@link com.oracle.graal.nodes.BeginNode BeginNode},</li> + * <li> + * {@link com.oracle.graal.nodes.LoopExitNode LoopExitNode},</li> + * <li> + * {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}</li> + * <li>{@link com.oracle.graal.nodes.MergeNode MergeNode}, resulting from merging two witnesses + * with different values for this anchor</li> + * </ul> + * + * <p> + * An {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} test results in the + * more-clueless of both scrutinees having its witness upgraded to that of the other (both + * scrutinees share the same {@link Witness Witness} instance from then on). For this reason, + * this field may also hold the anchors associated to an + * {@link com.oracle.graal.nodes.calc.ObjectEqualsNode ObjectEqualsNode} occurrence, ie nodes + * that can serve as {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} for the + * purposes of building a {@link com.oracle.graal.nodes.PiNode PiNode}. + * </p> + * + */ + private GuardingNode gn = null; + + /** + * Invariants of this class: + * <ul> + * <li>All fields holding null is ok, the hallmark of a {@link #clueless() clueless} witness. + * Another way for a witness to be clueless is by recording <code>java.lang.Object</code> as the + * seen type and nothing more.</li> + * <li>{@link #seen seen} may be null as long as the only hint being recorded is non-nullness</li> + * <li>A non-null value for {@link #seen seen} can't be tracked with NN, that combination + * amounts to IO and is tracked as such</li> + * <li>At most one of NN, CC, IO may be tracked at any given time</li> + * <li>A non-null CC or a non-null IO force {@link #seen seen} to be non-null</li> + * <li>{@link #seen seen} must be null or denote a non-interface reference type (ie, either a + * class-type or an array-type)</li> + * </ul> + */ + private boolean repOK() { + if (clueless()) { + assert level == LEVEL.CLUELESS; + return true; + } + if (level == LEVEL.NN) { + assert seen == null; + } + if (seen != null) { + assert !seen.isInterface(); + assert !seen.isPrimitive(); + } + boolean gnOK = gn instanceof BeginNode || gn instanceof LoopExitNode || gn instanceof MergeNode || gn instanceof FixedGuardNode; + assert gnOK; + return true; + } + + /** + * Helper method for readability in complex conditions. + */ + public boolean clueless() { + return cluelessAboutType() && cluelessAboutNonNullness(); + } + + /** + * Helper method for readability in complex conditions. + */ + public boolean cluelessAboutType() { + // TODO also clueless when `seen` is `java.lang.Object` + return seen == null; + } + + /** + * Helper method for readability in complex conditions. + */ + public boolean cluelessAboutNonNullness() { + return !atNonNull() && !atInstanceOf(); + } + + /** + * Whether this {@link Witness Witness} tracks information strictly more precise than that in + * the given {@link com.oracle.graal.compiler.common.type.ObjectStamp}. + */ + boolean knowsBetterThan(ObjectStamp other) { + return FlowUtil.isMorePrecise(asStamp(), other); + } + + /** + * Whether this {@link Witness Witness} tracks information strictly more precise than that in + * the {@link com.oracle.graal.compiler.common.type.ObjectStamp} of the given argument. + */ + boolean knowsBetterThan(ValueNode other) { + return knowsBetterThan((ObjectStamp) other.stamp()); + } + + /** + * Porcelain method for internal use only, invoked upon a Facade method being notified about + * checkcast or instanceof. + * + * @return whether the state was updated (iff the observation adds any new information) + */ + private boolean refinesSeenType(ResolvedJavaType observed) { + if (cluelessAboutType() || FlowUtil.isMorePrecise(observed, seen)) { + seen = observed; + return true; + } + return false; + } + + /** + * Updates this {@link Witness Witness} to account for an observation about the scrutinee being + * non-null. In case instanceof was observed, + * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode) + * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead + * + * @return whether this {@link Witness Witness} was updated (iff the observation adds any new + * information) + */ + public boolean trackNN(GuardingNode anchor) { + assert repOK(); + try { + if (atInstanceOf()) { + return false; + } + if (atCheckCast()) { + transition(LEVEL.IO, anchor); + return true; + } + if (!atNonNull()) { + transition(LEVEL.NN, anchor); + return true; + } + return false; + } finally { + assert repOK(); + } + } + + /** + * Updates this {@link Witness Witness} to account for an observation about the scrutinee + * conforming to the provided type. In case instanceof was observed, + * {@link #trackIO(com.oracle.graal.api.meta.ResolvedJavaType, com.oracle.graal.nodes.extended.GuardingNode) + * <code>trackIO(ResolvedJavaType, GuardingNode)</code>} should be invoked instead. + * + * @return true iff information was gained. + */ + public boolean trackCC(ResolvedJavaType observed, GuardingNode anchor) { + assert !observed.isInterface(); + assert anchor != null; + assert repOK(); + try { + boolean anchorObsolete = refinesSeenType(observed); + if (atInstanceOf()) { + /* + * Statechart: self-transition at IO, potential information gain. + */ + if (anchorObsolete) { + transition(LEVEL.IO, anchor); + return true; + } + return false; + } + if (anchorObsolete) { + if (!atNonNull()) { + /* Statechart: transition from clueless to CC. */ + transition(LEVEL.CC, anchor); + return true; + } else { + /* Statechart: transition from NN to IO. */ + transition(LEVEL.IO, anchor); + return true; + } + } + /* + * Statechart: self-transition from whichever the current state is to itself, without + * information gain. + */ + return false; + } finally { + assert repOK(); + } + } + + /** + * Updates this {@link Witness Witness} to account for an observation about the non-null + * scrutinee conforming to a type. + * + * @return whether this {@link Witness Witness} was updated (iff the observation adds any new + * information) + */ + public boolean trackIO(ResolvedJavaType observed, GuardingNode anchor) { + assert repOK(); + try { + boolean gotMorePreciseType = refinesSeenType(observed); + if (!atInstanceOf() || gotMorePreciseType) { + transition(LEVEL.IO, anchor); + return true; + } + return gotMorePreciseType; + } finally { + assert repOK(); + } + } + + /** + * Shallow cloning is enough because what's reachable from {@link Witness} is primitive or used + * read-only when merging states. + */ + @Override + public Witness clone() { + return new Witness(this); + } + + /** + * @return null for a clueless method, non-null otherwise. + */ + GuardingNode guard() { + return gn; + } + + /** + * Merges another state into this one, by mutating this object, the other is left as is. + */ + public void merge(Witness that, MergeNode merge) { + assert this.repOK(); + assert that.repOK(); + + if (clueless()) { + return; + } + + // umbrella type over the observations from both witnesses + ResolvedJavaType newSeen = (seen == null || that.seen == null) ? null : FlowUtil.widen(seen, that.seen); + + // preserve guarding node only if matches other, otherwise settle on `merge` + final GuardingNode resultGuard = guard() == that.guard() ? guard() : merge; + + /* + * guarantee on (both conformance and non-nullness) required from each input in order for + * the result to be able to offer such guarantee + */ + final boolean resultIO = atInstanceOf() && that.atInstanceOf(); + /* failing that, attempt to rescue type-conformance */ + final boolean resultCC = !resultIO && (!cluelessAboutType() && !that.cluelessAboutType()); + /* if all else fails, attempt to rescue non-nullness */ + final boolean resultNN = !resultIO && !resultCC && (isNonNull() && that.isNonNull()); + + seen = newSeen; + level = resultIO ? LEVEL.IO : resultCC ? LEVEL.CC : resultNN ? LEVEL.NN : LEVEL.CLUELESS; + gn = resultGuard; + + assert repOK(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(cluelessAboutType() ? "seen=?" : "seen=" + seen); + sb.append(";"); + sb.append("gn=" + gn); + return sb.toString(); + } + +}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -72,7 +72,7 @@ try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this)) { BasePhase.this.run(graph, context); phaseMetric.increment(); - if (dumpGraph) { + if (dumpGraph && Debug.isDumpEnabled()) { Debug.dump(graph, "After phase %s", getName()); } assert graph.verify(); @@ -81,13 +81,17 @@ } } + protected CharSequence createName() { + String s = BasePhase.this.getClass().getSimpleName(); + if (s.endsWith("Phase")) { + s = s.substring(0, s.length() - "Phase".length()); + } + return s; + } + public final CharSequence getName() { if (name == null) { - String s = BasePhase.this.getClass().getSimpleName(); - if (s.endsWith("Phase")) { - s = s.substring(0, s.length() - "Phase".length()); - } - name = s; + name = createName(); } return name; }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -888,37 +888,114 @@ return true; } + private static class SortState { + private Block block; + private NodeBitMap visited; + private NodeBitMap beforeLastLocation; + private List<ScheduledNode> sortedInstructions; + private List<FloatingReadNode> reads; + + SortState(Block block, NodeBitMap visited, NodeBitMap beforeLastLocation, List<ScheduledNode> sortedInstructions) { + this.block = block; + this.visited = visited; + this.beforeLastLocation = beforeLastLocation; + this.sortedInstructions = sortedInstructions; + this.reads = null; + } + + public Block currentBlock() { + return block; + } + + void markVisited(Node n) { + visited.mark(n); + } + + boolean isVisited(Node n) { + return visited.isMarked(n); + } + + void markBeforeLastLocation(FloatingReadNode n) { + beforeLastLocation.mark(n); + } + + void clearBeforeLastLocation(FloatingReadNode frn) { + beforeLastLocation.clear(frn); + } + + boolean isBeforeLastLocation(FloatingReadNode n) { + return beforeLastLocation.isMarked(n); + } + + void addRead(FloatingReadNode n) { + if (reads == null) { + reads = new ArrayList<>(); + } + reads.add(n); + } + + int readsSize() { + if (reads == null) { + return 0; + } + return reads.size(); + } + + void removeRead(ScheduledNode i) { + assert reads != null; + reads.remove(i); + } + + List<FloatingReadNode> readsSnapshot() { + assert reads != null; + return new ArrayList<>(reads); + } + + List<ScheduledNode> getSortedInstructions() { + return sortedInstructions; + } + + boolean containsInstruction(ScheduledNode i) { + return sortedInstructions.contains(i); + } + + void addInstruction(ScheduledNode i) { + sortedInstructions.add(i); + } + } + /** * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over * all inputs. This means that a node is added to the list after all its inputs have been * processed. */ private List<ScheduledNode> sortNodesWithinBlockLatest(Block b, NodeBitMap visited, NodeBitMap beforeLastLocation) { + SortState state = new SortState(b, visited, beforeLastLocation, new ArrayList<>(blockToNodesMap.get(b).size() + 2)); List<ScheduledNode> instructions = blockToNodesMap.get(b); - List<ScheduledNode> sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2); - List<FloatingReadNode> reads = new ArrayList<>(); if (memsched == MemoryScheduling.OPTIMAL) { for (ScheduledNode i : instructions) { if (i instanceof FloatingReadNode) { FloatingReadNode frn = (FloatingReadNode) i; if (frn.location().getLocationIdentity() != FINAL_LOCATION) { - reads.add(frn); + state.addRead(frn); if (nodesFor(b).contains(frn.getLastLocationAccess())) { - assert !beforeLastLocation.isMarked(frn); - beforeLastLocation.mark(frn); + assert !state.isBeforeLastLocation(frn); + state.markBeforeLastLocation(frn); } } } } } + for (ScheduledNode i : instructions) { - addToLatestSorting(b, i, sortedInstructions, visited, reads, beforeLastLocation); + addToLatestSorting(i, state); } - assert reads.size() == 0 : "not all reads are scheduled"; + assert state.readsSize() == 0 : "not all reads are scheduled"; // Make sure that last node gets really last (i.e. when a frame state successor hangs off // it). + List<ScheduledNode> sortedInstructions = state.getSortedInstructions(); Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1); if (lastSorted != b.getEndNode()) { int idx = sortedInstructions.indexOf(b.getEndNode()); @@ -944,40 +1021,39 @@ return sortedInstructions; } - private void processKillLocation(Block b, Node node, LocationIdentity identity, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, - NodeBitMap beforeLastLocation) { - for (FloatingReadNode frn : new ArrayList<>(reads)) { // TODO: change to iterator? + private void processKillLocation(Node node, LocationIdentity identity, SortState state) { + for (FloatingReadNode frn : state.readsSnapshot()) { LocationIdentity readLocation = frn.location().getLocationIdentity(); assert readLocation != FINAL_LOCATION; if (frn.getLastLocationAccess() == node) { assert identity == ANY_LOCATION || readLocation == identity : "location doesn't match: " + readLocation + ", " + identity; - beforeLastLocation.clear(frn); - } else if (!beforeLastLocation.isMarked(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) { - reads.remove(frn); - addToLatestSorting(b, frn, sortedInstructions, visited, reads, beforeLastLocation); + state.clearBeforeLastLocation(frn); + } else if (!state.isBeforeLastLocation(frn) && (readLocation == identity || (node != getCFG().graph.start() && ANY_LOCATION == identity))) { + state.removeRead(frn); + addToLatestSorting(frn, state); } } } - private void addUnscheduledToLatestSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) { + private void addUnscheduledToLatestSorting(VirtualState state, SortState sortState) { if (state != null) { // UnscheduledNodes should never be marked as visited. - if (visited.isMarked(state)) { + if (sortState.isVisited(state)) { throw new SchedulingError(); } for (Node input : state.inputs()) { if (input instanceof VirtualState) { - addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited, reads, beforeLastLocation); + addUnscheduledToLatestSorting((VirtualState) input, sortState); } else { - addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation); + addToLatestSorting((ScheduledNode) input, sortState); } } } } - private void addToLatestSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited, List<FloatingReadNode> reads, NodeBitMap beforeLastLocation) { - if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode) { + private void addToLatestSorting(ScheduledNode i, SortState state) { + if (i == null || state.isVisited(i) || cfg.getNodeToBlock().get(i) != state.currentBlock() || i instanceof PhiNode) { return; } @@ -988,45 +1064,45 @@ if (i instanceof LoopExitNode) { for (ProxyNode proxy : ((LoopExitNode) i).proxies()) { - addToLatestSorting(b, proxy, sortedInstructions, visited, reads, beforeLastLocation); + addToLatestSorting(proxy, state); } } for (Node input : i.inputs()) { if (input instanceof FrameState) { if (input != stateAfter) { - addUnscheduledToLatestSorting(b, (FrameState) input, sortedInstructions, visited, reads, beforeLastLocation); + addUnscheduledToLatestSorting((FrameState) input, state); } } else { if (!(i instanceof ProxyNode && input instanceof LoopExitNode)) { - addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation); + addToLatestSorting((ScheduledNode) input, state); } } } - if (memsched == MemoryScheduling.OPTIMAL && reads.size() != 0) { + if (memsched == MemoryScheduling.OPTIMAL && state.readsSize() != 0) { if (i instanceof MemoryCheckpoint.Single) { LocationIdentity identity = ((MemoryCheckpoint.Single) i).getLocationIdentity(); - processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation); + processKillLocation(i, identity, state); } else if (i instanceof MemoryCheckpoint.Multi) { for (LocationIdentity identity : ((MemoryCheckpoint.Multi) i).getLocationIdentities()) { - processKillLocation(b, i, identity, sortedInstructions, visited, reads, beforeLastLocation); + processKillLocation(i, identity, state); } } assert MemoryCheckpoint.TypeAssertion.correctType(i); } - addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited, reads, beforeLastLocation); - visited.mark(i); - addUnscheduledToLatestSorting(b, stateAfter, sortedInstructions, visited, reads, beforeLastLocation); + addToLatestSorting((ScheduledNode) i.predecessor(), state); + state.markVisited(i); + addUnscheduledToLatestSorting(stateAfter, state); // Now predecessors and inputs are scheduled => we can add this node. - if (!sortedInstructions.contains(i)) { - sortedInstructions.add(i); + if (!state.containsInstruction(i)) { + state.addInstruction(i); } - if (i instanceof FloatingReadNode) { - reads.remove(i); + if (state.readsSize() != 0 && i instanceof FloatingReadNode) { + state.removeRead(i); } }
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; @@ -37,7 +38,7 @@ @ServiceProvider(ReplacementsProvider.class) public class AMD64Substitutions implements ReplacementsProvider { - public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target) { + public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { if (Intrinsify.getValue()) { replacements.registerSubstitutions(ArraysSubstitutions.class); replacements.registerSubstitutions(StringSubstitutions.class);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,10 +22,11 @@ */ package com.oracle.graal.replacements.test; +import org.junit.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.test.*; /** * Tests the implementation of checkcast, allowing profiling information to be manually specified. @@ -41,7 +42,7 @@ } } - @LongTest + @Test public void test1() { test("asNumber", profile(), 111); test("asNumber", profile(Integer.class), 111); @@ -51,7 +52,7 @@ test("asNumberExt", profile(Long.class, Short.class), 111); } - @LongTest + @Test public void test2() { test("asString", profile(), "111"); test("asString", profile(String.class), "111"); @@ -67,27 +68,27 @@ test("asStringExt", profile(String.class), "111"); } - @LongTest + @Test public void test3() { test("asNumber", profile(), "111"); } - @LongTest + @Test public void test4() { test("asString", profile(String.class), 111); } - @LongTest + @Test public void test5() { test("asNumberExt", profile(), "111"); } - @LongTest + @Test public void test6() { test("asStringExt", profile(String.class), 111); } - @LongTest + @Test public void test7() { Throwable throwable = new Exception(); test("asThrowable", profile(), throwable); @@ -95,12 +96,12 @@ test("asThrowable", profile(Exception.class, Error.class), throwable); } - @LongTest + @Test public void test8() { test("arrayStore", new Object[100], "111"); } - @LongTest + @Test public void test801() { test("arrayFill", new Object[100], "111"); } @@ -197,7 +198,7 @@ return (Cloneable) o; } - @LongTest + @Test public void test9() { Object o = new Depth13(); test("asDepth12", profile(), o); @@ -205,7 +206,7 @@ test("asDepth12", profile(Depth13.class, Depth14.class), o); } - @LongTest + @Test public void test10() { Object o = new Depth13[3][]; test("asDepth12Arr", o);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -22,9 +22,10 @@ */ package com.oracle.graal.replacements.test; +import org.junit.*; + import com.oracle.graal.compiler.test.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.test.*; /** * Tests for {@link InstanceOfDynamicNode}. @@ -35,7 +36,7 @@ return value; } - @LongTest + @Test public void test100() { final Object nul = null; test("isStringDynamic", nul); @@ -43,7 +44,7 @@ test("isStringDynamic", Object.class); } - @LongTest + @Test public void test101() { final Object nul = null; test("isStringIntDynamic", nul); @@ -51,7 +52,7 @@ test("isStringIntDynamic", Object.class); } - @LongTest + @Test public void test103() { test("isInstanceDynamic", String.class, null); test("isInstanceDynamic", String.class, "object"); @@ -61,7 +62,7 @@ test("isInstanceDynamic", int.class, Object.class); } - @LongTest + @Test public void test104() { test("isInstanceIntDynamic", String.class, null); test("isInstanceIntDynamic", String.class, "object");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,6 +24,8 @@ import java.util.*; +import org.junit.*; + import com.oracle.graal.api.code.CompilationResult.Call; import com.oracle.graal.api.code.CompilationResult.Mark; import com.oracle.graal.api.code.CompilationResult.Site; @@ -34,7 +36,6 @@ import com.oracle.graal.replacements.test.CheckCastTest.Depth12; import com.oracle.graal.replacements.test.CheckCastTest.Depth13; import com.oracle.graal.replacements.test.CheckCastTest.Depth14; -import com.oracle.graal.test.*; /** * Tests the implementation of instanceof, allowing profiling information to be manually specified. @@ -54,7 +55,7 @@ } } - @LongTest + @Test public void test1() { test("isString", profile(), "object"); test("isString", profile(String.class), "object"); @@ -63,7 +64,7 @@ test("isString", profile(String.class), Object.class); } - @LongTest + @Test public void test2() { test("isStringInt", profile(), "object"); test("isStringInt", profile(String.class), "object"); @@ -72,7 +73,7 @@ test("isStringInt", profile(String.class), Object.class); } - @LongTest + @Test public void test201() { test("isStringIntComplex", profile(), "object"); test("isStringIntComplex", profile(String.class), "object"); @@ -81,7 +82,7 @@ test("isStringIntComplex", profile(String.class), Object.class); } - @LongTest + @Test public void test3() { Throwable throwable = new Exception(); test("isThrowable", profile(), throwable); @@ -93,7 +94,7 @@ test("isThrowable", profile(Exception.class, Error.class), Object.class); } - @LongTest + @Test public void test301() { onlyFirstIsException(new Exception(), new Error()); test("onlyFirstIsException", profile(), new Exception(), new Error()); @@ -102,7 +103,7 @@ test("onlyFirstIsException", profile(), new Error(), new Error()); } - @LongTest + @Test public void test4() { Throwable throwable = new Exception(); test("isThrowableInt", profile(), throwable); @@ -114,7 +115,7 @@ test("isThrowableInt", profile(Exception.class, Error.class), Object.class); } - @LongTest + @Test public void test5() { Map<?, ?> map = new HashMap<>(); test("isMap", profile(), map); @@ -127,7 +128,7 @@ test("isMap", profile(String.class, HashMap.class), Object.class); } - @LongTest + @Test public void test6() { Map<?, ?> map = new HashMap<>(); test("isMapInt", profile(), map); @@ -139,7 +140,7 @@ test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); } - @LongTest + @Test public void test7() { Object o = new Depth13(); test("isDepth12", profile(), o); @@ -153,7 +154,7 @@ test("isDepth12", profile(String.class, HashMap.class), o); } - @LongTest + @Test public void test8() { Object o = new Depth13(); test("isDepth12Int", profile(), o); @@ -259,7 +260,7 @@ } } - @LongTest + @Test public void test9() { MyCall callAt63 = new MyCall(63); MyMark markAt63 = new MyMark(63); @@ -276,11 +277,10 @@ return s1.offset - s2.offset; } - @LongTest + @Test public void test10() { - Mark[] noMarks = {}; Call callAt63 = new Call(null, 63, 5, true, null); - Mark markAt63 = new Mark(63, "1", noMarks); + Mark markAt63 = new Mark(63, "1"); test("compareSites", callAt63, callAt63); test("compareSites", callAt63, markAt63); test("compareSites", markAt63, callAt63); @@ -301,7 +301,7 @@ * The test exists in this source file as the transformation was originally motivated by the * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. */ - @LongTest + @Test public void testRemoveIntermediateMaterialization() { List<String> list = Arrays.asList("1", "2", "3", "4"); test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); @@ -356,7 +356,7 @@ return o instanceof D[]; } - @LongTest + @Test public void testArray() { Object aArray = new A[10]; test("isArrayOfA", aArray);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -25,7 +25,6 @@ import org.junit.*; import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; /** * Tests the implementation of {@code [A]NEWARRAY}. @@ -58,7 +57,7 @@ } } - @LongTest + @Test public void test1() { for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { test("new" + type + "Array7");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -27,7 +27,6 @@ import org.junit.*; import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; /** * Tests the implementation of {@code NEW}. @@ -57,12 +56,12 @@ } } - @LongTest + @Test public void test1() { test("newObject"); } - @LongTest + @Test public void test2() { test("newObjectTwice"); } @@ -71,37 +70,37 @@ return new Object(); } - @LongTest + @Test public void test3() { test("newObjectLoop", 100); } - @LongTest + @Test public void test4() { test("newBigObject"); } - @LongTest + @Test public void test5() { test("newSomeObject"); } - @LongTest + @Test public void test6() { test("newEmptyString"); } - @LongTest + @Test public void test7() { test("newString", "value"); } - @LongTest + @Test public void test8() { test("newHashMap", 31); } - @LongTest + @Test public void test9() { test("newRegression", true); }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -25,12 +25,13 @@ import java.lang.reflect.*; import java.util.*; +import org.junit.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.test.*; /** * Tests the lowering of the MULTIANEWARRAY instruction. @@ -86,7 +87,7 @@ Class<?> bottomClass; int[] dimensions; - @LongTest + @Test public void test1() { for (Class<?> clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) { bottomClass = clazz; @@ -117,7 +118,7 @@ return new Object[10][9][8]; } - @LongTest + @Test public void test2() { test("newMultiArrayException"); }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,6 +24,8 @@ import java.lang.reflect.*; +import org.junit.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; @@ -31,7 +33,6 @@ import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; -import com.oracle.graal.test.*; import com.oracle.graal.word.*; /** @@ -53,7 +54,7 @@ return installer.makeGraph(resolvedMethod, null, resolvedMethod, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); } - @LongTest + @Test public void construction() { long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; @@ -65,7 +66,7 @@ } } - @LongTest + @Test public void testArithmetic() { long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; @@ -102,7 +103,7 @@ } } - @LongTest + @Test public void testCompare() { long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; for (long word1 : words) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.nodes.spi.*; @@ -35,7 +36,7 @@ @ServiceProvider(ReplacementsProvider.class) public class GraalMethodSubstitutions implements ReplacementsProvider { - public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, Replacements replacements, TargetDescription target) { + public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) { for (Class<?> clazz : BoxingSubstitutions.getClasses()) { replacements.registerSubstitutions(clazz); }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Tue Apr 29 18:35:10 2014 +0200 @@ -32,15 +32,13 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.replacements.Snippet.Fold; -import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; /** * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering * snippet specific metrics. */ public class SnippetCounter implements Comparable<SnippetCounter> { - private static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter"); - /** * A group of related counters. */ @@ -107,7 +105,7 @@ /** * Creates a counter. - * + * * @param group the group to which the counter belongs. If this is null, the newly created * counter is disabled and {@linkplain #inc() incrementing} is a no-op. * @param name the name of the counter @@ -130,12 +128,20 @@ } /** + * We do not want to use the {@link LocationIdentity} of the {@link #value} field, so that the + * usage in snippets is always possible. If a method accesses the counter via the field and the + * snippet, the result might not be correct though. + */ + protected static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter"); + + /** * Increments the value of this counter. This method can be safely used in a snippet if it is * invoked on a compile-time constant {@link SnippetCounter} object. */ public void inc() { if (group != null) { - DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, SNIPPET_COUNTER_LOCATION); + long loadedValue = ObjectAccess.readLong(this, countOffset(), SNIPPET_COUNTER_LOCATION); + ObjectAccess.writeLong(this, countOffset(), loadedValue + 1, SNIPPET_COUNTER_LOCATION); } }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,9 +23,11 @@ package com.oracle.graal.replacements; import static com.oracle.graal.api.meta.LocationIdentity.*; + import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.debug.Debug.*; import static java.util.FormattableFlags.*; +import static com.oracle.graal.compiler.common.GraalOptions.*; import java.io.*; import java.lang.reflect.*; @@ -40,8 +42,8 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.GuardsStage; @@ -965,7 +967,15 @@ * if no FloatingReadNode is reading from this location, the kill to this location is fine. */ for (FloatingReadNode frn : replacee.graph().getNodes(FloatingReadNode.class)) { - assert !(kills.contains(frn.location().getLocationIdentity())) : frn + " reads from " + frn.location().getLocationIdentity() + " but " + replacee + " does not kill this location"; + LocationIdentity locationIdentity = frn.location().getLocationIdentity(); + if (SnippetCounters.getValue()) { + // accesses to snippet counters are artificially introduced and violate the memory + // semantics. + if (locationIdentity == SnippetCounter.SNIPPET_COUNTER_LOCATION) { + continue; + } + } + assert !kills.contains(locationIdentity) : frn + " reads from location \"" + locationIdentity + "\" but " + replacee + " does not kill this location"; } return true; }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,8 +24,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.*; @@ -36,7 +34,7 @@ /** * Compares two arrays with the same length. */ -public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable { +public class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable { /** {@link Kind} of the arrays to compare. */ private final Kind kind; @@ -131,7 +129,7 @@ public static native boolean equals(double[] array1, double[] array2, int length); @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { Variable result = gen.newVariable(Kind.Int); gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length)); gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,15 +24,14 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; -public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { +public class BitCountNode extends FloatingNode implements LIRLowerable, Canonicalizable { @Input private ValueNode value; @@ -65,7 +64,7 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { Variable result = gen.newVariable(Kind.Int); gen.emitBitCount(result, gen.operand(value)); gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,15 +24,14 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; -public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { +public class BitScanForwardNode extends FloatingNode implements LIRLowerable, Canonicalizable { @Input private ValueNode value; @@ -72,7 +71,7 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { Variable result = gen.newVariable(Kind.Int); gen.emitBitScanForward(result, gen.operand(value)); gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,15 +24,14 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; -public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { +public class BitScanReverseNode extends FloatingNode implements LIRLowerable, Canonicalizable { @Input private ValueNode value; @@ -79,7 +78,7 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { Variable result = gen.newVariable(Kind.Int); gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value)); gen.setResult(this, result);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -24,15 +24,14 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; -public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { +public class ReverseBytesNode extends FloatingNode implements LIRLowerable, Canonicalizable { @Input private ValueNode value; @@ -66,9 +65,9 @@ } @Override - public void generate(NodeLIRBuilder gen) { + public void generate(NodeLIRBuilderTool gen) { Variable result = gen.newVariable(value.getKind()); - gen.getLIRGenerator().emitByteSwap(result, gen.operand(value)); + gen.getLIRGeneratorTool().emitByteSwap(result, gen.operand(value)); gen.setResult(this, result); } }
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java Tue Apr 29 18:35:10 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,28 +35,28 @@ */ public class SPARC extends Architecture { - // @formatter:off - public static final RegisterCategory CPU = new RegisterCategory("CPU"); public static final RegisterCategory FPU = new RegisterCategory("FPU"); // General purpose registers - public static final Register r0 = new Register(0, 0, "g0", CPU); - public static final Register r1 = new Register(1, 1, "g1", CPU); - public static final Register r2 = new Register(2, 2, "g2", CPU); - public static final Register r3 = new Register(3, 3, "g3", CPU); - public static final Register r4 = new Register(4, 4, "g4", CPU); - public static final Register r5 = new Register(5, 5, "g5", CPU); - public static final Register r6 = new Register(6, 6, "g6", CPU); - public static final Register r7 = new Register(7, 7, "g7", CPU); - public static final Register r8 = new Register(8, 8, "o0", CPU); - public static final Register r9 = new Register(9, 9, "o1", CPU); + public static final Register r0 = new Register(0, 0, "g0", CPU); + public static final Register r1 = new Register(1, 1, "g1", CPU); + public static final Register r2 = new Register(2, 2, "g2", CPU); + public static final Register r3 = new Register(3, 3, "g3", CPU); + public static final Register r4 = new Register(4, 4, "g4", CPU); + public static final Register r5 = new Register(5, 5, "g5", CPU); + public static final Register r6 = new Register(6, 6, "g6", CPU); + public static final Register r7 = new Register(7, 7, "g7", CPU); + + public static final Register r8 = new Register(8, 8, "o0", CPU); + public static final Register r9 = new Register(9, 9, "o1", CPU); public static final Register r10 = new Register(10, 10, "o2", CPU); public static final Register r11 = new Register(11, 11, "o3", CPU); public static final Register r12 = new Register(12, 12, "o4", CPU); public static final Register r13 = new Register(13, 13, "o5", CPU); public static final Register r14 = new Register(14, 14, "o6", CPU); public static final Register r15 = new Register(15, 15, "o7", CPU); + public static final Register r16 = new Register(16, 16, "l0", CPU); public static final Register r17 = new Register(17, 17, "l1", CPU); public static final Register r18 = new Register(18, 18, "l2", CPU); @@ -65,6 +65,7 @@ public static final Register r21 = new Register(21, 21, "l5", CPU); public static final Register r22 = new Register(22, 22, "l6", CPU); public static final Register r23 = new Register(23, 23, "l7", CPU); + public static final Register r24 = new Register(24, 24, "i0", CPU); public static final Register r25 = new Register(25, 25, "i1", CPU); public static final Register r26 = new Register(26, 26, "i2", CPU); @@ -113,12 +114,14 @@ public static final Register sp = o6; public static final Register fp = i6; + // @formatter:off public static final Register[] cpuRegisters = { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31 }; + // @formatter:on // Floating point registers public static final Register f0 = new Register(32, 0, "f0", FPU); @@ -130,6 +133,43 @@ public static final Register f6 = new Register(38, 6, "f6", FPU); public static final Register f7 = new Register(39, 7, "f7", FPU); + public static final Register f8 = new Register(40, 8, "f8", FPU); + public static final Register f9 = new Register(41, 9, "f9", FPU); + public static final Register f10 = new Register(42, 10, "f10", FPU); + public static final Register f11 = new Register(43, 11, "f11", FPU); + public static final Register f12 = new Register(44, 12, "f12", FPU); + public static final Register f13 = new Register(45, 13, "f13", FPU); + public static final Register f14 = new Register(46, 14, "f14", FPU); + public static final Register f15 = new Register(47, 15, "f15", FPU); + + public static final Register f16 = new Register(48, 16, "f16", FPU); + public static final Register f17 = new Register(49, 17, "f17", FPU); + public static final Register f18 = new Register(50, 18, "f18", FPU); + public static final Register f19 = new Register(51, 19, "f19", FPU); + public static final Register f20 = new Register(52, 20, "f20", FPU); + public static final Register f21 = new Register(53, 21, "f21", FPU); + public static final Register f22 = new Register(54, 22, "f22", FPU); + public static final Register f23 = new Register(55, 23, "f23", FPU); + + public static final Register f24 = new Register(56, 24, "f24", FPU); + public static final Register f25 = new Register(57, 25, "f25", FPU); + public static final Register f26 = new Register(58, 26, "f26", FPU); + public static final Register f27 = new Register(59, 27, "f27", FPU); + public static final Register f28 = new Register(60, 28, "f28", FPU); + public static final Register f29 = new Register(61, 29, "f29", FPU); + public static final Register f30 = new Register(62, 30, "f30", FPU); + public static final Register f31 = new Register(63, 31, "f31", FPU); + + // @formatter:off + public static final Register[] fpuRegisters = { + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31 + }; + // @formatter:on + + // @formatter:off public static final Register[] allRegisters = { // CPU r0, r1, r2, r3, r4, r5, r6, r7, @@ -138,9 +178,16 @@ r24, r25, r26, r27, r28, r29, r30, r31, // FPU f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31 }; + // @formatter:on - // @formatter:on + /** + * Stack bias for stack and frame pointer loads. + */ + public static final int STACK_BIAS = 0x7ff; public SPARC() { super("SPARC", 8, ByteOrder.BIG_ENDIAN, false, allRegisters, LOAD_STORE | STORE_STORE, 1, r31.encoding + 1, 8);
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * 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.test; - -import java.util.*; - -import org.junit.*; -import org.junit.runners.*; -import org.junit.runners.model.*; - -public class GraalLongUnitTest extends BlockJUnit4ClassRunner { - - public GraalLongUnitTest(Class<?> klass) throws InitializationError { - super(klass); - } - - @Override - protected List<FrameworkMethod> computeTestMethods() { - List<FrameworkMethod> methods = new ArrayList<>(5); - methods.addAll(getTestClass().getAnnotatedMethods(Test.class)); - methods.addAll(getTestClass().getAnnotatedMethods(LongTest.class)); - return methods; - } -}
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -26,14 +26,12 @@ import java.util.*; import org.junit.*; -import org.junit.runner.*; /** * Base class for Graal tests. * <p> * This contains common utility methods that are used in multiple test projects. */ -@RunWith(GraalLongUnitTest.class) public class GraalTest { protected Method getMethod(String methodName) {
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * 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.test; - -import java.lang.annotation.*; - -/* copy of org.junit.Test */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD}) -public @interface LongTest { - - static final class None extends Throwable { - - private static final long serialVersionUID = 1L; - - private None() { - } - } - - Class<? extends Throwable> expected() default None.class; - - long timeout() default 0L; -}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java Tue Apr 29 18:35:10 2014 +0200 @@ -88,13 +88,12 @@ public abstract CallTarget getTargetCallTarget(); - public DirectCallNode getCallNode() { + public Node getCallNode() { Object receiver = stackFrame.getLocal(getNotifyIndex()); - if (receiver instanceof DirectCallNode) { - return (DirectCallNode) receiver; - } else { - return null; + if (receiver instanceof DirectCallNode || receiver instanceof IndirectCallNode) { + return (Node) receiver; } + return null; } /** @@ -146,10 +145,9 @@ } /** - * This class represents a frame that is taken from the - * {@link RootCallTarget#callProxy(VirtualFrame)} method. + * This class represents a frame that is taken from the {@link OptimizedCallTarget#callProxy} + * method. */ - @SuppressWarnings("javadoc") public static final class CallTargetFrame extends HotSpotFrameInstance { public static final Method METHOD; static {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Apr 29 18:35:10 2014 +0200 @@ -241,7 +241,6 @@ if (inliningPerformed) { return; } - inliningPerformed = true; TruffleInliningHandler handler = new TruffleInliningHandler(new DefaultInliningPolicy()); TruffleInliningResult result = handler.decideInlining(this, 0); performInlining(result); @@ -249,6 +248,10 @@ } private static void performInlining(TruffleInliningResult result) { + if (result.getCallTarget().inliningPerformed) { + return; + } + result.getCallTarget().inliningPerformed = true; for (TruffleInliningProfile profile : result) { profile.getCallNode().inline(); TruffleInliningResult recursiveResult = profile.getRecursiveResult(); @@ -272,7 +275,7 @@ if (profiledReturnTypeAssumption == null) { if (TruffleReturnTypeSpeculation.getValue()) { CompilerDirectives.transferToInterpreter(); - profiledReturnType = result.getClass(); + profiledReturnType = (result == null ? null : result.getClass()); profiledReturnTypeAssumption = Truffle.getRuntime().createAssumption("Profiled Return Type"); } } else if (profiledReturnType != null) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Apr 29 18:35:10 2014 +0200 @@ -63,7 +63,7 @@ private final RuntimeProvider runtime; private final TruffleCache truffleCache; - private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class}; + private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class}; public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Apr 29 18:35:10 2014 +0200 @@ -54,7 +54,7 @@ @Option(help = "Enable automatic inlining of call targets") public static final OptionValue<Boolean> TruffleFunctionInlining = new OptionValue<>(true); @Option(help = "Maximum number of Graal IR nodes during partial evaluation") - public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(45000); + public static final OptionValue<Integer> TruffleGraphMaxNodes = new OptionValue<>(200000); @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit") public static final OptionValue<Integer> TruffleInliningMaxCallerSize = new OptionValue<>(2250); @Option(help = "Skip inlining candidate if its tree size exceeds this limit")
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java Tue Apr 29 18:35:10 2014 +0200 @@ -94,7 +94,7 @@ int deepNodeCount; TruffleInliningResult recursiveResult; boolean recursiveCall = false; - if (depth > MAXIMUM_RECURSIVE_DEPTH) { + if (target.inliningPerformed || depth > MAXIMUM_RECURSIVE_DEPTH) { deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true); recursiveResult = null; } else {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -23,11 +23,10 @@ package com.oracle.graal.truffle.nodes.frame; import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; -public class ForceMaterializeNode extends FixedWithNextNode implements LIRGenLowerable { +public class ForceMaterializeNode extends FixedWithNextNode implements LIRLowerable { @Input private ValueNode object; @@ -36,7 +35,7 @@ this.object = object; } - public void generate(NodeLIRBuilder generator) { + public void generate(NodeLIRBuilderTool generator) { // nothing to do }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Tue Apr 29 18:35:10 2014 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.nodes.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase; import com.oracle.graal.phases.tiers.*; public class IterativeInliningPhase extends AbstractInliningPhase { @@ -70,9 +71,14 @@ new DeadCodeEliminationPhase().apply(graph); - if (ConditionalElimination.getValue() && OptCanonicalizer.getValue()) { + boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue(); + if (reduceOrEliminate && OptCanonicalizer.getValue()) { canonicalizer.apply(graph, context); - new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context); + if (FlowSensitiveReduction.getValue()) { + new IterativeFlowSensitiveReductionPhase(canonicalizer).apply(graph, context); + } else { + new IterativeConditionalEliminationPhase(canonicalizer).apply(graph, context); + } } if (!progress) { break;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Apr 29 18:35:10 2014 +0200 @@ -579,15 +579,29 @@ } else { // all inputs are virtual: check if they're compatible and without identity boolean compatible = true; + boolean hasIdentity = false; ObjectState firstObj = objStates[0]; for (int i = 0; i < objStates.length; i++) { ObjectState obj = objStates[i]; - boolean hasIdentity = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual); - if (hasIdentity || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) { + hasIdentity |= obj.virtual.hasIdentity(); + boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual); + if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) { compatible = false; break; } } + if (compatible && hasIdentity) { + // we still need to check whether this value is referenced by any other phi + outer: for (PhiNode otherPhi : merge.phis().filter(otherPhi -> otherPhi != phi)) { + for (int i = 0; i < objStates.length; i++) { + ObjectState otherPhiValueState = getObjectState(states.get(i), otherPhi.valueAt(i)); + if (Arrays.asList(objStates).contains(otherPhiValueState)) { + compatible = false; + break outer; + } + } + } + } if (compatible) { VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * <h3>Inserting Extra Nodes into the AST Transparently</h3> + * + * <p> + * The {@link Node} class provides a callback that is invoked whenever a node is adopted in an AST + * by insertion or replacement. Node classes can override the {@code onAdopt()} method to run extra + * functionality upon adoption. + * </p> + * + * <p> + * This test demonstrates how node instances of a specific class can be automatically wrapped in + * extra nodes when they are inserted into the AST. + * </p> + */ +public class OnAdoptTest { + + static class Root extends RootNode { + + @Child private Base child1; + @Child private Base child2; + + public Root(Base child1, Base child2) { + super(null); + this.child1 = child1; + this.child2 = child2; + } + + @Override + public Object execute(VirtualFrame frame) { + return child1.executeInt(frame) + child2.executeInt(frame); + } + + } + + abstract static class Base extends Node { + public abstract int executeInt(VirtualFrame frame); + } + + static class Wrapper extends Base { + + @Child private Base wrappee; + + public Wrapper(Base wrappee) { + this.wrappee = wrappee; + } + + @Override + public int executeInt(VirtualFrame frame) { + return 1 + wrappee.executeInt(frame); + } + + } + + abstract static class GenBase extends Base { + + private final int k; + + public GenBase(int k) { + this.k = k; + } + + @Override + public int executeInt(VirtualFrame frame) { + return k; + } + + } + + static class Gen extends GenBase { + public Gen(int k) { + super(k); + } + } + + static class GenWrapped extends GenBase { + + public GenWrapped(int k) { + super(k); + } + + @Override + protected void onAdopt() { + Wrapper w = new Wrapper(this); + this.replace(w); + } + + } + + @Test + public void testOnInsert() { + TruffleRuntime runtime = Truffle.getRuntime(); + Base b1 = new Gen(11); + Base b2 = new GenWrapped(11); + Root r = new Root(b1, b2); + CallTarget ct = runtime.createCallTarget(r); + Object result = ct.call(); + Assert.assertEquals(23, result); + } + +}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Tue Apr 29 18:35:10 2014 +0200 @@ -34,12 +34,21 @@ /** * Returns the name of this resource holding a guest language program. An example would be the * name of a guest language source code file. - * + * * @return the name of the guest language program */ String getName(); /** + * Returns a short version of the name of the resource holding a guest language program (as + * described in @getName). For example, this could be just the name of the file, rather than a + * full path. + * + * @return the short name of the guest language program + */ + String getShortName(); + + /** * The normalized, canonical name of the file. */ String getPath();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue Apr 29 18:35:10 2014 +0200 @@ -31,21 +31,21 @@ /** * Returns the object representing the source program that contains this section. - * + * * @return the source object */ Source getSource(); /** * Returns 1-based line number of the first character in this source section (inclusive). - * + * * @return the starting line number */ int getStartLine(); /** * Returns the 1-based column number of the first character in this source section (inclusive). - * + * * @return the starting column number */ int getStartColumn(); @@ -55,7 +55,7 @@ * <p> * The complete text of the source that contains this section can be retrieved via * {@link Source#getCode()}. - * + * * @return the starting character index */ int getCharIndex(); @@ -65,7 +65,7 @@ * <p> * The complete text of the source that contains this section can be retrieved via * {@link Source#getCode()}. - * + * * @return the number of characters in the section */ int getCharLength(); @@ -73,42 +73,54 @@ /** * Returns the index of the text position immediately following the last character in the * section. - * + * * @return the end position of the section */ int getCharEndIndex(); /** * Returns the identifier of this source section that is used for printing the section. - * + * * @return the identifier of the section */ String getIdentifier(); /** * Returns text of the code represented by this source section. - * + * * @return the code as a String object */ String getCode(); /** + * Returns a short description of the source section, using just the file name, rather than its + * full path. + * + * @return a short description of the source section + */ + String getShortDescription(); + + /** * Singleton instance with no content. */ SourceSection NULL = new NullSourceSection() { + @Override public Source getSource() { return null; } + @Override public int getStartLine() { return 0; } + @Override public int getStartColumn() { return 0; } + @Override public int getCharIndex() { return 0; } @@ -118,18 +130,26 @@ return 0; } + @Override public int getCharEndIndex() { return 0; } + @Override public String getIdentifier() { return null; } + @Override public String getCode() { return null; } + @Override + public String getShortDescription() { + return "short"; + } + }; }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java Tue Apr 29 18:35:10 2014 +0200 @@ -40,9 +40,7 @@ boolean isVirtualFrame(); - DirectCallNode getCallNode(); + Node getCallNode(); CallTarget getCallTarget(); - - CallTarget getTargetCallTarget(); }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java Tue Apr 29 18:35:10 2014 +0200 @@ -53,7 +53,7 @@ * a character index. The (row,column) coordinates of a newline character should never appear in * a text section. * <p> - * + * * @param source object representing the complete source program that contains this section * @param identifier an identifier used when printing the section * @param startLine the 1-based number of the start line of the section @@ -102,6 +102,10 @@ return getSource().getCode().substring(charIndex, charIndex + charLength); } + public final String getShortDescription() { + return String.format("%s:%d", source.getShortName(), startLine); + } + @Override public String toString() { return String.format("%s:%d", source.getName(), startLine);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Tue Apr 29 18:35:10 2014 +0200 @@ -191,8 +191,12 @@ if (newChild == this) { throw new IllegalStateException("The parent of a node can never be the node itself."); } + boolean isInserted = newChild.parent == null; newChild.parent = this; newChild.adoptHelper(); + if (isInserted) { + newChild.onAdopt(); + } } private void adoptHelper() { @@ -209,8 +213,12 @@ if (newChild == this) { throw new IllegalStateException("The parent of a node can never be the node itself."); } + boolean isInserted = newChild.parent == null; newChild.parent = this; newChild.adoptUnadoptedHelper(); + if (isInserted) { + newChild.onAdopt(); + } } private void adoptUnadoptedHelper() { @@ -332,7 +340,6 @@ } private void traceRewrite(Node newNode, CharSequence reason) { - if (TruffleOptions.TraceRewritesFilterFromCost != null) { if (filterByKind(this, TruffleOptions.TraceRewritesFilterFromCost)) { return; @@ -352,8 +359,21 @@ return; } + final SourceSection reportedSourceSection = getEncapsulatingSourceSection(); + PrintStream out = System.out; - out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason); + out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s%s%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason != null && reason.length() > 0 ? reason + : "unknown", reportedSourceSection != null ? " at " + reportedSourceSection.getShortDescription() : ""); + } + + /** + * Subclasses of {@link Node} can implement this method to execute extra functionality when a + * node is effectively inserted into the AST. The {@code onAdopt} callback is called after the + * node has been effectively inserted, and it is guaranteed to be called only once for any given + * node. + */ + protected void onAdopt() { + // empty default } private static String formatNodeInfo(Node node) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Tue Apr 29 18:35:10 2014 +0200 @@ -70,7 +70,7 @@ /** * Gets the canonical representation of a source file, whose contents will be read lazily and * then cached. - * + * * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read */ public Source get(String fileName, boolean reset) { @@ -227,6 +227,11 @@ } @Override + public String getShortName() { + return name; + } + + @Override public String getCode() { return code; } @@ -292,6 +297,11 @@ } @Override + public String getShortName() { + return file.getName(); + } + + @Override public String getCode() { if (code == null || timeStamp != file.lastModified()) { try {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Tue Apr 29 18:35:10 2014 +0200 @@ -44,7 +44,7 @@ * <li>After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U} * <li>After execution of function {@code f3}: {@code I->G} * </ol> - * */ + */ public abstract class SLAbstractDispatchNode extends Node { protected static final int INLINE_CACHE_SIZE = 2;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Tue Apr 29 18:23:17 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Tue Apr 29 18:35:10 2014 +0200 @@ -29,7 +29,7 @@ * there is always the danger of a spurious {@link NullPointerException}. Representing the guest * language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended * practice. - * */ + */ public final class SLNull { /**
--- a/mx.cmd Tue Apr 29 18:23:17 2014 +0200 +++ b/mx.cmd Tue Apr 29 18:35:10 2014 +0200 @@ -1,1 +1,1 @@ -python mxtool/mx.py %* +python %~dp0/mxtool/mx.py %*
--- a/mx/mx_graal.py Tue Apr 29 18:23:17 2014 +0200 +++ b/mx/mx_graal.py Tue Apr 29 18:35:10 2014 +0200 @@ -26,7 +26,7 @@ # # ---------------------------------------------------------------------------------------------------- -import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO +import os, sys, shutil, zipfile, tarfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO, socket from os.path import join, exists, dirname, basename, getmtime from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER from outputparser import OutputParser, ValuesMatcher @@ -35,6 +35,7 @@ import sanitycheck import itertools import json, textwrap +import fnmatch # This works because when mx loads this file, it makes sure __file__ gets an absolute path _graal_home = dirname(dirname(__file__)) @@ -162,49 +163,124 @@ rmIfExists(mx.distribution('GRAAL').path) def export(args): - """create a GraalVM zip file for distribution""" + """create archives of builds split by vmbuild and vm""" parser = ArgumentParser(prog='mx export') - parser.add_argument('--omit-vm-build', action='store_false', dest='vmbuild', help='omit VM build step') - parser.add_argument('--omit-dist-init', action='store_false', dest='distInit', help='omit class files and IDE configurations from distribution') - parser.add_argument('zipfile', nargs=REMAINDER, metavar='zipfile') - args = parser.parse_args(args) - tmp = tempfile.mkdtemp(prefix='tmp', dir=_graal_home) - if args.vmbuild: - # Make sure the product VM binary is up to date - with VM(vmbuild='product'): - build([]) + # collect data about export + infos = dict() + infos['timestamp'] = time.time() + + hgcfg = mx.HgConfig() + hgcfg.check() + infos['revision'] = hgcfg.tip('.') + ('+' if hgcfg.isDirty('.') else '') + # TODO: infos['repository'] + + infos['jdkversion'] = str(mx.java().version) + + infos['architecture'] = _arch() + infos['platform'] = mx.get_os() + + if mx.get_os != 'windows': + pass + # infos['ccompiler'] + # infos['linker'] + + infos['hostname'] = socket.gethostname() - mx.log('Copying Java sources and mx files...') - mx.run(('hg archive -I graal -I mx -I mxtool -I mx.sh ' + tmp).split()) + def _writeJson(suffix, properties): + d = infos.copy() + for k, v in properties.iteritems(): + assert not d.has_key(k) + d[k] = v + + jsonFileName = 'export-' + suffix + '.json' + with open(jsonFileName, 'w') as f: + print >> f, json.dumps(d) + return jsonFileName + + + def _genFileName(archivtype, middle): + idPrefix = infos['revision'] + '_' + idSuffix = '.tar.gz' + return join(_graal_home, "graalvm_" + archivtype + "_" + idPrefix + middle + idSuffix) + + def _genFileArchPlatformName(archivtype, middle): + return _genFileName(archivtype, infos['platform'] + '_' + infos['architecture'] + '_' + middle) + + + # archive different build types of hotspot + for vmBuild in _vmbuildChoices: + jdkpath = join(_jdksDir(), vmBuild) + if not exists(jdkpath): + mx.logv("skipping " + vmBuild) + continue - # Copy the GraalVM JDK - mx.log('Copying GraalVM JDK...') - src = _jdk() - dst = join(tmp, basename(src)) - shutil.copytree(src, dst) - zfName = join(_graal_home, 'graalvm-' + mx.get_os() + '.zip') - zf = zipfile.ZipFile(zfName, 'w') - for root, _, files in os.walk(tmp): - for f in files: - name = join(root, f) - arcname = name[len(tmp) + 1:] - zf.write(join(tmp, name), arcname) + tarName = _genFileArchPlatformName('basejdk', vmBuild) + mx.logv("creating basejdk " + tarName) + vmSet = set() + with tarfile.open(tarName, 'w:gz') as tar: + for root, _, files in os.walk(jdkpath): + if basename(root) in _vmChoices.keys(): + # TODO: add some assert to check path assumption + vmSet.add(root) + continue + + for f in files: + name = join(root, f) + # print name + tar.add(name, name) + + n = _writeJson("basejdk-" + vmBuild, {'vmbuild' : vmBuild}) + tar.add(n, n) + + # create a separate archive for each VM + for vm in vmSet: + bVm = basename(vm) + vmTarName = _genFileArchPlatformName('vm', vmBuild + '_' + bVm) + mx.logv("creating vm " + vmTarName) - # create class files and IDE configurations - if args.distInit: - mx.log('Creating class files...') - mx.run('mx build'.split(), cwd=tmp) - mx.log('Creating IDE configurations...') - mx.run('mx ideinit'.split(), cwd=tmp) + debugFiles = set() + with tarfile.open(vmTarName, 'w:gz') as tar: + for root, _, files in os.walk(vm): + for f in files: + # TODO: mac, windows, solaris? + if any(map(f.endswith, [".debuginfo"])): + debugFiles.add(f) + else: + name = join(root, f) + # print name + tar.add(name, name) + + n = _writeJson("vm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm}) + tar.add(n, n) - # clean up temp directory - mx.log('Cleaning up...') - shutil.rmtree(tmp) + if len(debugFiles) > 0: + debugTarName = _genFileArchPlatformName('debugfilesvm', vmBuild + '_' + bVm) + mx.logv("creating debugfilesvm " + debugTarName) + with tarfile.open(debugTarName, 'w:gz') as tar: + for f in debugFiles: + name = join(root, f) + # print name + tar.add(name, name) + + n = _writeJson("debugfilesvm-" + vmBuild + "-" + bVm, {'vmbuild' : vmBuild, 'vm' : bVm}) + tar.add(n, n) - mx.log('Created distribution in ' + zfName) + # graal directory + graalDirTarName = _genFileName('classfiles', 'javac') + mx.logv("creating graal " + graalDirTarName) + with tarfile.open(graalDirTarName, 'w:gz') as tar: + for root, _, files in os.walk("graal"): + for f in [f for f in files if not f.endswith('.java')]: + name = join(root, f) + # print name + tar.add(name, name) + + n = _writeJson("graal", {'javacompiler' : 'javac'}) + tar.add(n, n) + def _run_benchmark(args, availableBenchmarks, runBenchmark): @@ -861,7 +937,7 @@ projectscp = mx.classpath(projs) if whitelist: - classes = list(set(classes) & set(whitelist)) + classes = [c for c in classes if any((glob.match(c) for glob in whitelist))] if len(classes) != 0: f_testfile = open(testfile, 'w') @@ -905,10 +981,8 @@ _unittestHelpSuffix = """ Unittest options: - --short-only run short testcases only - --long-only run long testcases only - --baseline-whitelist run only testcases which are known to - work with the baseline compiler + --whitelist run only testcases which are included + in the given whitelist To avoid conflicts with VM options '--' can be used as delimiter. @@ -945,10 +1019,7 @@ formatter_class=RawDescriptionHelpFormatter, epilog=_unittestHelpSuffix, ) - group = parser.add_mutually_exclusive_group() - group.add_argument('--short-only', action='store_true', help='run short testcases only') - group.add_argument('--long-only', action='store_true', help='run long testcases only') - parser.add_argument('--baseline-whitelist', action='store_true', help='run baseline testcases only') + parser.add_argument('--whitelist', help='run testcases specified in whitelist only', metavar='<path>') ut_args = [] delimiter = False @@ -968,33 +1039,19 @@ parsed_args, args = parser.parse_known_args(ut_args) whitelist = None - if parsed_args.baseline_whitelist: - baseline_whitelist_file = 'test/baseline_whitelist.txt' + if parsed_args.whitelist: try: - with open(join(_graal_home, baseline_whitelist_file)) as fp: - whitelist = [l.rstrip() for l in fp.readlines()] + with open(join(_graal_home, parsed_args.whitelist)) as fp: + whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')] except IOError: - mx.log('warning: could not read baseline whitelist: ' + baseline_whitelist_file) + mx.log('warning: could not read whitelist: ' + parsed_args.whitelist) - if parsed_args.long_only: - annotations = ['@LongTest', '@Parameters'] - elif parsed_args.short_only: - annotations = ['@Test'] - else: - annotations = ['@Test', '@LongTest', '@Parameters'] - - _unittest(args, annotations, whitelist=whitelist) + _unittest(args, ['@Test', '@Parameters'], whitelist=whitelist) def shortunittest(args): - """alias for 'unittest --short-only'{0}""" - - args.insert(0, '--short-only') - unittest(args) + """alias for 'unittest --whitelist test/whitelist_shortunittest.txt'{0}""" -def longunittest(args): - """alias for 'unittest --long-only'{0}""" - - args.insert(0, '--long-only') + args = ['--whitelist', 'test/whitelist_shortunittest.txt'] + args unittest(args) def buildvms(args): @@ -1104,6 +1161,11 @@ unittest([]) tasks.append(t.stop()) + with VM('server', 'product'): # hosted mode + t = Task('UnitTests-BaselineCompiler:hosted-product') + unittest(['--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler']) + tasks.append(t.stop()) + for vmbuild in ['fastdebug', 'product']: for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): t = Task(str(test) + ':' + vmbuild) @@ -1723,14 +1785,14 @@ """make truffle.jar""" # Test with the built classes - _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters']) + _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@Parameters']) # We use the DSL processor as the starting point for the classpath - this # therefore includes the DSL processor, the DSL and the API. packagejar(mx.classpath("com.oracle.truffle.dsl.processor").split(os.pathsep), "truffle.jar", None, "com.oracle.truffle.dsl.processor.TruffleProcessor") # Test with the JAR - _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'], "truffle.jar:") + _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@Parameters'], "truffle.jar:") def isGraalEnabled(vm): @@ -1953,7 +2015,6 @@ 'gate' : [gate, '[-options]'], 'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'], 'unittest' : [unittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix], - 'longunittest' : [longunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix], 'makejmhdeps' : [makejmhdeps, ''], 'shortunittest' : [shortunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix], 'jacocoreport' : [jacocoreport, '[output directory]'],
--- a/mx/projects Tue Apr 29 18:23:17 2014 +0200 +++ b/mx/projects Tue Apr 29 18:35:10 2014 +0200 @@ -42,19 +42,19 @@ library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar library@DACAPO_SCALA@sha1=59b64c974662b5cf9dbd3cf9045d293853dd7a51 -library@OKRA@path=lib/okra-1.8.jar -library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8.jar -library@OKRA@sourcePath=lib/okra-1.8-src.jar -library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-src.jar +library@OKRA@path=lib/okra-1.9.jar +library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9.jar +library@OKRA@sourcePath=lib/okra-1.9-src.jar +library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-src.jar -library@OKRA_WITH_SIM@path=lib/okra-1.8-with-sim.jar -library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim.jar -library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar -library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar +library@OKRA_WITH_SIM@path=lib/okra-1.9-with-sim.jar +library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim.jar +library@OKRA_WITH_SIM@sourcePath=lib/okra-1.9-with-sim-src.jar +library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.9-with-sim-src.jar library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar -library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar -library@JAVA_ALLOCATION_INSTRUMENTER@sha1=64c0a5329fbcb8284640e58d83252e0a3b08c23e +library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-c7e3525a6b90.jar +library@JAVA_ALLOCATION_INSTRUMENTER@sha1=128eb20a4cd3362a4d8b94614e66647808a2e37c library@VECMATH@path=lib/vecmath-1.3.1.jar library@VECMATH@urls=http://mirrors.ibiblio.org/pub/mirrors/maven/java3d/jars/vecmath-1.3.1.jar @@ -426,6 +426,7 @@ project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler@javaCompliance=1.8 project@com.oracle.graal.compiler@annotationProcessors=com.oracle.graal.service.processor +project@com.oracle.graal.compiler@annotationProcessorForDependents=true project@com.oracle.graal.compiler@workingSets=Graal # graal.compiler.amd64
--- a/mxtool/mx.py Tue Apr 29 18:23:17 2014 +0200 +++ b/mxtool/mx.py Tue Apr 29 18:35:10 2014 +0200 @@ -608,6 +608,17 @@ else: return None + def isDirty(self, sDir, abortOnError=True): + try: + return len(subprocess.check_output(['hg', 'status', '-R', sDir])) > 0 + except OSError: + warn(self.missing) + except subprocess.CalledProcessError: + if abortOnError: + abort('failed to get status') + else: + return None + class Suite: def __init__(self, mxDir, primary, load=True): self.dir = dirname(mxDir) @@ -1800,11 +1811,13 @@ parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)') parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects') parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects') - parser.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not') - parser.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='<path>') parser.add_argument('--jdt-warning-as-error', action='store_true', help='convert all Eclipse batch compiler warnings to errors') parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings') - parser.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>') + compilerSelect = parser.add_mutually_exclusive_group() + compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>') + compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='<path>') + compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not') + if suppliedParser: parser.add_argument('remainder', nargs=REMAINDER, metavar='...') @@ -1886,12 +1899,11 @@ cp = classpath(p.name, includeSelf=True) sourceDirs = p.source_dirs() - mustBuild = args.force - if not mustBuild: + buildReason = 'forced build' if args.force else None + if not buildReason: for dep in p.all_deps([], False): if dep.name in built: - mustBuild = True - + buildReason = dep.name + ' rebuilt' jasminAvailable = None javafilelist = [] @@ -1940,20 +1952,19 @@ if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) < os.path.getmtime(src)): shutil.copyfile(src, dst) - if not mustBuild: + if not buildReason: for javafile in javafiles: classfile = TimeStampFile(outputDir + javafile[len(sourceDir):-len('java')] + 'class') if not classfile.exists() or classfile.isOlderThan(javafile): - mustBuild = True + buildReason = 'class file(s) out of date' break aps = p.annotation_processors() apsOutOfDate = p.update_current_annotation_processors_file() if apsOutOfDate: - logv('[annotation processors for {0} changed]'.format(p.name)) - mustBuild = True - - if not mustBuild: + buildReason = 'annotation processor(s) changed' + + if not buildReason: logv('[all class files for {0} are up to date - skipping]'.format(p.name)) continue @@ -1985,10 +1996,14 @@ toBeDeleted = [argfileName] try: + + def logCompilation(p, compiler, reason): + log('Compiling Java sources for {} with {}... [{}]'.format(p.name, compiler, reason)) + if not jdtJar: mainJava = java() if not args.error_prone: - log('Compiling Java sources for {0} with javac...'.format(p.name)) + logCompilation(p, 'javac', buildReason) javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] if jdk.debug_port is not None: javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)] @@ -1999,7 +2014,7 @@ javacCmd.append('-XDignore.symbol.file') run(javacCmd) else: - log('Compiling Java sources for {0} with javac (with error-prone)...'.format(p.name)) + logCompilation(p, 'javac (with error-prone)', buildReason) javaArgs = ['-Xmx1g'] javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] javacArgs += processorArgs @@ -2008,7 +2023,7 @@ javacArgs.append('-XDignore.symbol.file') run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs) else: - log('Compiling Java sources for {0} with JDT...'.format(p.name)) + logCompilation(p, 'JDT', buildReason) jdtVmArgs = ['-Xmx1g', '-jar', jdtJar] @@ -3843,7 +3858,7 @@ def ideinit(args, refreshOnly=False, buildProcessorJars=True): - """(re)generate Eclipse and NetBeans project configurations""" + """(re)generate Eclipse, NetBeans and Intellij project configurations""" eclipseinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars) netbeansinit(args, refreshOnly=refreshOnly, buildProcessorJars=buildProcessorJars) intellijinit(args, refreshOnly=refreshOnly) @@ -3981,7 +3996,13 @@ try: log('Generating {2} for {0} in {1}'.format(p.name, out, docDir)) projectJava = java(p.javaCompliance) - run([java().javadoc, memory, + + # Once https://bugs.openjdk.java.net/browse/JDK-8041628 is fixed, + # this should be reverted to: + # javadocExe = java().javadoc + javadocExe = projectJava.javadoc + + run([javadocExe, memory, '-XDignore.symbol.file', '-classpath', cp, '-quiet', @@ -3991,6 +4012,7 @@ '-source', str(projectJava.javaCompliance), '-bootclasspath', projectJava.bootclasspath(), '-extdirs', projectJava.extdirs()] + + ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) + links + extraArgs + nowarnAPI + @@ -4028,115 +4050,19 @@ '-quiet', '-d', out, '-sourcepath', sp] + + ([] if java().javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) + links + extraArgs + nowarnAPI + list(pkgs)) log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir)) -class Chunk: - def __init__(self, content, ldelim, rdelim=None): - lindex = content.find(ldelim) - if rdelim is not None: - rindex = content.find(rdelim) - else: - rindex = lindex + len(ldelim) - self.ldelim = ldelim - self.rdelim = rdelim - if lindex != -1 and rindex != -1 and rindex > lindex: - self.text = content[lindex + len(ldelim):rindex] - else: - self.text = None - - def replace(self, content, repl): - lindex = content.find(self.ldelim) - if self.rdelim is not None: - rindex = content.find(self.rdelim) - rdelimLen = len(self.rdelim) - else: - rindex = lindex + len(self.ldelim) - rdelimLen = 0 - old = content[lindex:rindex + rdelimLen] - return content.replace(old, repl) - -# Post-process an overview-summary.html file to move the -# complete overview to the top of the page -def _fix_overview_summary(path, topLink): - """ - Processes an "overview-summary.html" generated by javadoc to put the complete - summary text above the Packages table. - """ - - # This uses scraping and so will break if the relevant content produced by javadoc changes in any way! - with open(path) as fp: - content = fp.read() - - chunk1 = Chunk(content, """<div class="header"> -<div class="subTitle"> -<div class="block">""", """</div> -</div> -<p>See: <a href="#overview.description">Description</a></p> -</div>""") - - chunk2 = Chunk(content, """<div class="contentContainer"><a name="overview.description"> -<!-- --> -</a> -<div class="block">""", """</div> -</div> -<!-- ======= START OF BOTTOM NAVBAR ====== -->""") - - assert chunk1.text, 'Could not find header section in ' + path - assert chunk2.text, 'Could not find footer section in ' + path - - content = chunk1.replace(content, '<div class="header"><div class="subTitle"><div class="block">' + topLink + chunk2.text + '</div></div></div>') - content = chunk2.replace(content, '') - - with open(path, 'w') as fp: - fp.write(content) - - -# Post-process a package-summary.html file to move the -# complete package description to the top of the page -def _fix_package_summary(path): - """ - Processes an "overview-summary.html" generated by javadoc to put the complete - summary text above the Packages table. - """ - - # This uses scraping and so will break if the relevant content produced by javadoc changes in any way! - with open(path) as fp: - content = fp.read() - - chunk1 = Chunk(content, """<div class="header"> -<h1 title="Package" class="title">Package""", """<p>See: <a href="#package.description">Description</a></p> -</div>""") - - chunk2 = Chunk(content, """<a name="package.description"> -<!-- --> -</a>""", """</div> -</div> -<!-- ======= START OF BOTTOM NAVBAR ====== -->""") - - if chunk1.text: - if chunk2.text: - repl = re.sub(r'<h2 title=(.*) Description</h2>', r'<h1 title=\1</h1>', chunk2.text, 1) - content = chunk1.replace(content, '<div class="header">' + repl + '</div></div>') - content = chunk2.replace(content, '') - - with open(path, 'w') as fp: - fp.write(content) - else: - log('warning: Could not find package description detail section in ' + path) - - else: - # no package description given - pass - def site(args): """creates a website containing javadoc and the project dependency graph""" parser = ArgumentParser(prog='site') parser.add_argument('-d', '--base', action='store', help='directory for generated site', required=True, metavar='<dir>') + parser.add_argument('--tmp', action='store', help='directory to use for intermediate results', metavar='<dir>') parser.add_argument('--name', action='store', help='name of overall documentation', required=True, metavar='<name>') parser.add_argument('--overview', action='store', help='path to the overview content for overall documentation', required=True, metavar='<path>') parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)') @@ -4147,7 +4073,7 @@ args = parser.parse_args(args) args.base = os.path.abspath(args.base) - tmpbase = tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base)) + tmpbase = args.tmp if args.tmp else tempfile.mkdtemp(prefix=basename(args.base) + '.', dir=dirname(args.base)) unified = join(tmpbase, 'all') exclude_packages_arg = [] @@ -4196,6 +4122,9 @@ '--arg', '@-windowtitle', '--arg', '@' + title, '--arg', '@-doctitle', '--arg', '@' + title, '--arg', '@-overview', '--arg', '@' + args.overview] + exclude_packages_arg + projects_arg + extra_javadoc_args) + + if exists(unified): + shutil.rmtree(unified) os.rename(join(tmpbase, 'javadoc'), unified) # Generate dependency graph with Graphviz @@ -4249,29 +4178,17 @@ with open(html, 'w') as fp: print >> fp, '<html><body><object data="{}.svg" type="image/svg+xml"></object></body></html>'.format(args.dot_output_base) - top = join(tmpbase, 'all', 'overview-summary.html') - for root, _, files in os.walk(tmpbase): - for f in files: - if f == 'overview-summary.html': - path = join(root, f) - topLink = '' - if top != path: - link = os.path.relpath(join(tmpbase, 'all', 'index.html'), dirname(path)) - topLink = '<p><a href="' + link + '", target="_top"><b>[return to the overall ' + args.name + ' documentation]</b></a></p>' - _fix_overview_summary(path, topLink) - elif f == 'package-summary.html': - path = join(root, f) - _fix_package_summary(path) - - if exists(args.base): shutil.rmtree(args.base) - shutil.move(tmpbase, args.base) + if args.tmp: + shutil.copytree(tmpbase, args.base) + else: + shutil.move(tmpbase, args.base) print 'Created website - root is ' + join(args.base, 'all', 'index.html') finally: - if exists(tmpbase): + if not args.tmp and exists(tmpbase): shutil.rmtree(tmpbase) def _kwArg(kwargs): @@ -4345,6 +4262,7 @@ parser = ArgumentParser(prog='exportlibs') parser.add_argument('-b', '--base', action='store', help='base name of archive (default: libs)', default='libs', metavar='<path>') + parser.add_argument('-a', '--include-all', action='store_true', help="include all defined libaries") parser.add_argument('--arc', action='store', choices=['tgz', 'tbz2', 'tar', 'zip'], default='tgz', help='the type of the archive to create') parser.add_argument('--no-sha1', action='store_false', dest='sha1', help='do not create SHA1 signature of archive') parser.add_argument('--no-md5', action='store_false', dest='md5', help='do not create MD5 signature of archive') @@ -4365,9 +4283,44 @@ else: logv('[already added ' + path + ']') - for lib in _libs.itervalues(): - if len(lib.urls) != 0 or args.include_system_libs: - add(lib.get_path(resolve=True), lib.path) + libsToExport = set() + if args.include_all: + for lib in _libs.itervalues(): + libsToExport.add(lib) + else: + def isValidLibrary(dep): + if dep in _libs.iterkeys(): + lib = _libs[dep] + if len(lib.urls) != 0 or args.include_system_libs: + return lib + return None + + # iterate over all project dependencies and find used libraries + for p in _projects.itervalues(): + for dep in p.deps: + r = isValidLibrary(dep) + if r: + libsToExport.add(r) + + # a library can have other libraries as dependency + size = 0 + while size != len(libsToExport): + size = len(libsToExport) + for lib in libsToExport.copy(): + for dep in lib.deps: + r = isValidLibrary(dep) + if r: + libsToExport.add(r) + + for lib in libsToExport: + add(lib.get_path(resolve=True), lib.path) + if lib.sha1: + add(lib.get_path(resolve=True) + ".sha1", lib.path + ".sha1") + if lib.sourcePath: + add(lib.get_source_path(resolve=True), lib.sourcePath) + if lib.sourceSha1: + add(lib.get_source_path(resolve=True) + ".sha1", lib.sourcePath + ".sha1") + if args.extras: for e in args.extras: if os.path.isdir(e):
--- a/src/share/vm/code/debugInfoRec.cpp Tue Apr 29 18:23:17 2014 +0200 +++ b/src/share/vm/code/debugInfoRec.cpp Tue Apr 29 18:35:10 2014 +0200 @@ -235,16 +235,13 @@ int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) { - // It's always a space win to share and Graal generates quite a bit - // of scopes data so always enable the sharing logic with Graal. - // Presumably this is disabled in regular HotSpot because it makes - // recording more expensive? -#ifndef GRAAL - // Only pull this trick if non-safepoint recording - // is enabled, for now. - if (!recording_non_safepoints()) + if (FLAG_IS_DEFAULT(ShareDebugInfo)) { + if (!ShareDebugInfo && !recording_non_safepoints()) { + return serialized_null; + } + } else if (!ShareDebugInfo) { return serialized_null; -#endif + } NOT_PRODUCT(++dir_stats.chunks_queried); int stream_length = stream()->position() - stream_offset;
--- a/src/share/vm/code/nmethod.cpp Tue Apr 29 18:23:17 2014 +0200 +++ b/src/share/vm/code/nmethod.cpp Tue Apr 29 18:35:10 2014 +0200 @@ -142,6 +142,7 @@ int handler_table_size; int nul_chk_table_size; int oops_size; + int metadata_size; void note_nmethod(nmethod* nm) { nmethod_count += 1; @@ -151,6 +152,7 @@ insts_size += nm->insts_size(); stub_size += nm->stub_size(); oops_size += nm->oops_size(); + metadata_size += nm->metadata_size(); scopes_data_size += nm->scopes_data_size(); scopes_pcs_size += nm->scopes_pcs_size(); dependencies_size += nm->dependencies_size(); @@ -161,11 +163,13 @@ if (nmethod_count == 0) return; tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name); if (total_size != 0) tty->print_cr(" total in heap = %d", total_size); + if (nmethod_count != 0) tty->print_cr(" header = %d", nmethod_count * sizeof(nmethod)); if (relocation_size != 0) tty->print_cr(" relocation = %d", relocation_size); if (consts_size != 0) tty->print_cr(" constants = %d", consts_size); if (insts_size != 0) tty->print_cr(" main code = %d", insts_size); if (stub_size != 0) tty->print_cr(" stub code = %d", stub_size); if (oops_size != 0) tty->print_cr(" oops = %d", oops_size); + if (metadata_size != 0) tty->print_cr(" metadata = %d", metadata_size); if (scopes_data_size != 0) tty->print_cr(" scopes data = %d", scopes_data_size); if (scopes_pcs_size != 0) tty->print_cr(" scopes pcs = %d", scopes_pcs_size); if (dependencies_size != 0) tty->print_cr(" dependencies = %d", dependencies_size); @@ -180,12 +184,14 @@ int native_relocation_size; int native_insts_size; int native_oops_size; + int native_metadata_size; void note_native_nmethod(nmethod* nm) { native_nmethod_count += 1; native_total_size += nm->size(); native_relocation_size += nm->relocation_size(); native_insts_size += nm->insts_size(); native_oops_size += nm->oops_size(); + native_metadata_size += nm->metadata_size(); } void print_native_nmethod_stats() { if (native_nmethod_count == 0) return; @@ -194,6 +200,7 @@ if (native_relocation_size != 0) tty->print_cr(" N. relocation = %d", native_relocation_size); if (native_insts_size != 0) tty->print_cr(" N. main code = %d", native_insts_size); if (native_oops_size != 0) tty->print_cr(" N. oops = %d", native_oops_size); + if (native_metadata_size != 0) tty->print_cr(" N. metadata = %d", native_metadata_size); } }; @@ -229,11 +236,18 @@ #ifdef GRAAL static java_nmethod_stats_struct graal_java_nmethod_stats; #endif +#ifdef SHARK +static java_nmethod_stats_struct shark_java_nmethod_stats; +#endif static java_nmethod_stats_struct unknown_java_nmethod_stats; static native_nmethod_stats_struct native_nmethod_stats; static pc_nmethod_stats_struct pc_nmethod_stats; +static void note_native_wrapper_nmethod(nmethod* nm) { + native_nmethod_stats.note_native_nmethod(nm); +} + static void note_java_nmethod(nmethod* nm) { #ifdef COMPILER1 if (nm->is_compiled_by_c1()) { @@ -250,6 +264,11 @@ graal_java_nmethod_stats.note_nmethod(nm); } else #endif +#ifdef SHARK + if (nm->is_compiled_by_shark()) { + shark_java_nmethod_stats.note_nmethod(nm); + } else +#endif { unknown_java_nmethod_stats.note_nmethod(nm); } @@ -556,7 +575,7 @@ code_buffer, frame_size, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); - if (nm != NULL) note_java_nmethod(nm); + if (nm != NULL) note_native_wrapper_nmethod(nm); if (PrintAssembly && nm != NULL) { Disassembler::decode(nm); } @@ -3083,9 +3102,14 @@ #ifdef GRAAL graal_java_nmethod_stats.print_nmethod_stats("Graal"); #endif +#ifdef SHARK + shark_java_nmethod_stats.print_nmethod_stats("Shark"); +#endif unknown_java_nmethod_stats.print_nmethod_stats("Unknown"); DebugInformationRecorder::print_statistics(); +#ifndef PRODUCT pc_nmethod_stats.print_pc_stats(); +#endif Dependencies::print_statistics(); if (xtty != NULL) xtty->tail("statistics"); }
--- a/src/share/vm/graal/graalGlobals.hpp Tue Apr 29 18:23:17 2014 +0200 +++ b/src/share/vm/graal/graalGlobals.hpp Tue Apr 29 18:35:10 2014 +0200 @@ -52,6 +52,9 @@ COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true, \ "Bootstrap Graal before running Java main method")) \ \ + product(bool, ForceGraalInitialization, false, \ + "Force VM to initialize the compiler even if not used") \ + \ product(intx, TraceGraal, 0, \ "Trace level for Graal") \ \
--- a/src/share/vm/prims/jni.cpp Tue Apr 29 18:23:17 2014 +0200 +++ b/src/share/vm/prims/jni.cpp Tue Apr 29 18:35:10 2014 +0200 @@ -5176,6 +5176,9 @@ #ifdef GRAAL // GraalCompiler needs to have been created in compileBroker.cpp GraalCompiler* graal_compiler = GraalCompiler::instance(); + if (ForceGraalInitialization && graal_compiler == NULL) { + graal_compiler = new GraalCompiler(); + } if (graal_compiler != NULL) { graal_compiler->initialize(); } else {
--- a/src/share/vm/runtime/globals.hpp Tue Apr 29 18:23:17 2014 +0200 +++ b/src/share/vm/runtime/globals.hpp Tue Apr 29 18:35:10 2014 +0200 @@ -980,6 +980,9 @@ product(bool, PrintNMethodStatistics, false, \ "Print a summary statistic for the generated nmethods") \ \ + product(bool, ShareDebugInfo, IS_GRAAL_DEFINED, \ + "Always tries to share similar debug info inside a nmethod") \ + \ diagnostic(bool, PrintNMethods, false, \ "Print assembly code for nmethods when generated") \ \
--- a/src/share/vm/runtime/thread.cpp Tue Apr 29 18:23:17 2014 +0200 +++ b/src/share/vm/runtime/thread.cpp Tue Apr 29 18:35:10 2014 +0200 @@ -1680,9 +1680,11 @@ if (_thread_stat != NULL) delete _thread_stat; #ifdef GRAAL - if (GraalCounterSize > 0 && graal_counters_include(threadObj())) { - for (int i = 0; i < GraalCounterSize; i++) { - _graal_old_thread_counters[i] += _graal_counters[i]; + if (GraalCounterSize > 0) { + if (graal_counters_include(threadObj())) { + for (int i = 0; i < GraalCounterSize; i++) { + _graal_old_thread_counters[i] += _graal_counters[i]; + } } FREE_C_HEAP_ARRAY(jlong, _graal_counters, mtInternal); }
--- a/test/baseline_whitelist.txt Tue Apr 29 18:23:17 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -com.oracle.graal.jtt.loop.Loop03 -com.oracle.graal.jtt.loop.Loop04 -com.oracle.graal.jtt.loop.Loop08 -com.oracle.graal.jtt.loop.Loop11 -com.oracle.graal.jtt.bytecode.BC_iadd -com.oracle.graal.jtt.bytecode.BC_iadd2 -com.oracle.graal.jtt.bytecode.BC_iadd3 -com.oracle.graal.jtt.bytecode.BC_ifeq_2 -com.oracle.graal.jtt.bytecode.BC_ifeq_3 -com.oracle.graal.jtt.bytecode.BC_ifeq -com.oracle.graal.jtt.bytecode.BC_aload_3 -com.oracle.graal.jtt.bytecode.BC_aload_2 -com.oracle.graal.jtt.bytecode.BC_aload_1 -com.oracle.graal.jtt.bytecode.BC_aload_0 -com.oracle.graal.jtt.bytecode.BC_areturn -com.oracle.graal.jtt.bytecode.BC_freturn -com.oracle.graal.jtt.bytecode.BC_iconst -com.oracle.graal.jtt.bytecode.BC_ireturn -com.oracle.graal.jtt.bytecode.BC_lreturn
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/whitelist_baseline.txt Tue Apr 29 18:35:10 2014 +0200 @@ -0,0 +1,19 @@ +# com.oracle.graal.jtt.loop.Loop03 +# com.oracle.graal.jtt.loop.Loop04 +# com.oracle.graal.jtt.loop.Loop08 +# com.oracle.graal.jtt.loop.Loop11 +com.oracle.graal.jtt.bytecode.BC_iadd +com.oracle.graal.jtt.bytecode.BC_iadd2 +com.oracle.graal.jtt.bytecode.BC_iadd3 +com.oracle.graal.jtt.bytecode.BC_ifeq_2 +com.oracle.graal.jtt.bytecode.BC_ifeq_3 +com.oracle.graal.jtt.bytecode.BC_ifeq +com.oracle.graal.jtt.bytecode.BC_aload_3 +com.oracle.graal.jtt.bytecode.BC_aload_2 +com.oracle.graal.jtt.bytecode.BC_aload_1 +com.oracle.graal.jtt.bytecode.BC_aload_0 +com.oracle.graal.jtt.bytecode.BC_areturn +com.oracle.graal.jtt.bytecode.BC_freturn +com.oracle.graal.jtt.bytecode.BC_iconst +com.oracle.graal.jtt.bytecode.BC_ireturn +com.oracle.graal.jtt.bytecode.BC_lreturn