# HG changeset patch # User Christos Kotselidis # Date 1384029247 -3600 # Node ID a5b5e1ebab81aca04b907c0e3125a1b7fe4625d4 # Parent ad2434911b69b16a77ddfd6a27f727cb20e09764# Parent bb85b81258a0ad8f10425b95efcfab0bad415580 Merge diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Sat Nov 09 21:34:07 2013 +0100 @@ -194,7 +194,7 @@ * @return the constant value */ public long asLong() { - assert getKind() == Kind.Long || getKind().getStackKind() == Kind.Int; + assert getKind().isNumericInteger(); return primitive; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Sat Nov 09 21:34:07 2013 +0100 @@ -117,6 +117,24 @@ } /** + * Checks whether this type is a Java primitive type representing an integer number. + * + * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}. + */ + public boolean isNumericInteger() { + return isStackInt || this == Kind.Long; + } + + /** + * Checks whether this type is a Java primitive type representing a floating point number. + * + * @return {@code true} if this is {@link #Float} or {@link #Double}. + */ + public boolean isNumericFloat() { + return this == Kind.Float || this == Kind.Double; + } + + /** * Returns the kind corresponding to the Java type string. * * @param typeString the Java type string diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Sat Nov 09 21:34:07 2013 +0100 @@ -70,9 +70,11 @@ /** * Encodes a deoptimization action and a deoptimization reason in an integer value. * + * @param speculationId a speculation ID returned by SpeculationLog.addSpeculation + * * @return the encoded value as an integer */ - Constant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason); + Constant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int speculationId); DeoptimizationReason decodeDeoptReason(Constant constant); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64AsmOptions.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64AsmOptions.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64AsmOptions.java Sat Nov 09 21:34:07 2013 +0100 @@ -23,11 +23,9 @@ package com.oracle.graal.asm.amd64; public class AMD64AsmOptions { - - public static int Atomics = 0; - public static boolean UseNormalNop = false; - public static boolean UseAddressNop = true; - public static boolean UseIncDec = true; - public static boolean UseXmmLoadAndClearUpper = true; - public static boolean UseXmmRegToRegMoveAll = true; + public static final boolean UseNormalNop = false; + public static final boolean UseAddressNop = true; + public static final boolean UseIncDec = true; + public static final boolean UseXmmLoadAndClearUpper = true; + public static final boolean UseXmmRegToRegMoveAll = true; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Sat Nov 09 21:34:07 2013 +0100 @@ -524,26 +524,10 @@ // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,. // The ZF is set if the compared values were equal, and cleared otherwise. public final void cmpxchgl(Register reg, AMD64Address adr) { // cmpxchg - if ((Atomics & 2) != 0) { - // caveat: no instructionmark, so this isn't relocatable. - // Emit a synthetic, non-atomic, CAS equivalent. - // Beware. The synthetic form sets all ICCs, not just ZF. - // cmpxchg r,[m] is equivalent to X86.rax, = CAS (m, X86.rax, r) - cmpl(rax, adr); - movl(rax, adr); - if (reg.equals(rax)) { - Label l = new Label(); - jccb(ConditionFlag.NotEqual, l); - movl(adr, reg); - bind(l); - } - } else { - - prefix(adr, reg); - emitByte(0x0F); - emitByte(0xB1); - emitOperandHelper(reg, adr); - } + prefix(adr, reg); + emitByte(0x0F); + emitByte(0xB1); + emitOperandHelper(reg, adr); } public final void cvtsd2ss(Register dst, AMD64Address src) { @@ -860,12 +844,7 @@ } public final void lock() { - if ((Atomics & 1) != 0) { - // Emit either nothing, a NOP, or a NOP: prefix - emitByte(0x90); - } else { - emitByte(0xF0); - } + emitByte(0xF0); } public final void movapd(Register dst, Register src) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java --- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Sat Nov 09 21:34:07 2013 +0100 @@ -355,39 +355,75 @@ } /** - * Emit code to build a 64-bit pointer from a compressed-oop and the associated base and shift. - * We only emit this if base and shift are not both zero. + * Emits code to build a 64-bit pointer from a compressed value and the associated base and + * shift. The compressed value could represent either a normal oop or a klass ptr. If the + * compressed value is 0, the uncompressed must also be 0. We only emit this if base and shift + * are not both zero. + * + * @param result the register containing the compressed value on input and the uncompressed ptr + * on output + * @param base the amount to be added to the compressed value + * @param shift the number of bits to shift left the compressed value + * @param testForNull true if the compressed value might be null */ - public void emitCompressedOopDecode(Value result, long narrowOopBase, int narrowOopShift) { - if (narrowOopBase == 0) { - emit("shl", result, result, Constant.forInt(narrowOopShift)); - } else if (narrowOopShift == 0) { - // only use add if result is not starting as null (unsigned compare) - emitCompare(result, Constant.forLong(0), "eq", false, true); - emit("add", result, result, Constant.forLong(narrowOopBase)); - emitConditionalMove(result, Constant.forLong(0), result, 64); + public void emitCompressedOopDecode(Value result, long base, int shift, boolean testForNull) { + assert (base != 0 || shift != 0); + assert (!isConstant(result)); + if (base == 0) { + // we don't have to test for null if shl is the only operation + emitForceUnsigned("shl", result, result, Constant.forInt(shift)); + } else if (shift == 0) { + // only use add if result is not starting as null (test only if testForNull is true) + emitWithOptionalTestForNull(testForNull, "add", result, result, Constant.forLong(base)); } else { - // only use mad if result is not starting as null (unsigned compare) - emitCompare(result, Constant.forLong(0), "eq", false, true); - emitTextFormattedInstruction("mad_u64 ", result, result, Constant.forInt(1 << narrowOopShift), Constant.forLong(narrowOopBase)); - emitConditionalMove(result, Constant.forLong(0), result, 64); + // only use mad if result is not starting as null (test only if testForNull is true) + emitWithOptionalTestForNull(testForNull, "mad", result, result, Constant.forInt(1 << shift), Constant.forLong(base)); } } /** - * Emit code to build a 32-bit compressed pointer from a full 64-bit pointer using the - * associated base and shift. We only emit this if base and shift are not both zero. + * Emits code to build a compressed value from a full 64-bit pointer using the associated base + * and shift. The compressed value could represent either a normal oop or a klass ptr. If the + * ptr is 0, the compressed value must also be 0. We only emit this if base and shift are not + * both zero. + * + * @param result the register containing the 64-bit pointer on input and the compressed value on + * output + * @param base the amount to be subtracted from the 64-bit pointer + * @param shift the number of bits to shift right the 64-bit pointer + * @param testForNull true if the 64-bit pointer might be null */ - public void emitCompressedOopEncode(Value result, long narrowOopBase, int narrowOopShift) { - if (narrowOopBase != 0) { - // only use sub if result is not starting as null (unsigned compare) + public void emitCompressedOopEncode(Value result, long base, int shift, boolean testForNull) { + assert (base != 0 || shift != 0); + assert (!isConstant(result)); + if (base != 0) { + // only use sub if result is not starting as null (test only if testForNull is true) + emitWithOptionalTestForNull(testForNull, "sub", result, result, Constant.forLong(base)); + } + if (shift != 0) { + // note that the shr can still be done even if the result is null + emitForceUnsigned("shr", result, result, Constant.forInt(shift)); + } + } + + /** + * Emits code for the requested mnemonic on the result and sources. In addition, if testForNull + * is true, surrounds the instruction with code that will guarantee that if the result starts as + * 0, it will remain 0. + * + * @param testForNull true if we want to add the code to check for and preserve null + * @param mnemonic the instruction to be applied (without size prefix) + * @param result the register which is both an input and the final output + * @param sources the sources for the mnemonic instruction + */ + private void emitWithOptionalTestForNull(boolean testForNull, String mnemonic, Value result, Value... sources) { + if (testForNull) { emitCompare(result, Constant.forLong(0), "eq", false, true); - emit("sub", result, result, Constant.forLong(narrowOopBase)); + } + emitForceUnsigned(mnemonic, result, sources); + if (testForNull) { emitConditionalMove(result, Constant.forLong(0), result, 64); } - if (narrowOopShift != 0) { - emit("shr", result, result, Constant.forInt(narrowOopShift)); - } } /** diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Sat Nov 09 21:34:07 2013 +0100 @@ -279,7 +279,7 @@ } private void emitIntegerTest(Value a, Value b) { - assert a.getKind().getStackKind() == Kind.Int || a.getKind() == Kind.Long; + assert a.getKind().isNumericInteger(); if (LIRValueUtil.isVariable(b)) { append(new AMD64TestOp(load(b), loadNonConst(a))); } else { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Sat Nov 09 21:34:07 2013 +0100 @@ -27,12 +27,14 @@ * This class extends KernelTester and provides a base class * for which the HSAIL code comes from the Graal compiler. */ -import com.oracle.graal.hotspot.hsail.*; +import static com.oracle.graal.phases.GraalOptions.*; -import java.lang.reflect.Method; import java.io.*; +import java.lang.reflect.*; -import static com.oracle.graal.phases.GraalOptions.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.hsail.*; +import com.oracle.graal.options.*; public abstract class GraalKernelTester extends KernelTester { @@ -75,4 +77,14 @@ boolean canExecuteCalls = runningOnSimulator(); return (canGenerateCalls && canExecuteCalls); } + + public static OptionValue getOptionFromField(Class declaringClass, String fieldName) { + try { + Field f = declaringClass.getDeclaredField(fieldName); + f.setAccessible(true); + return (OptionValue) f.get(null); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/InstanceOfTest.java --- /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/InstanceOfTest.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,97 @@ +/* + * 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 com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; +import org.junit.Test; + +/** + * Tests instanceof operator. Requires correct support for decompression of klass ptrs. + */ +public class InstanceOfTest extends GraalKernelTester { + + static final int NUM = 20; + + abstract static class Shape { + + public abstract float getArea(); + } + + static class Circle extends Shape { + + private float radius; + + Circle(float r) { + radius = r; + } + + @Override + public float getArea() { + return (float) (Math.PI * radius * radius); + } + } + + static class Square extends Shape { + + private float len; + + Square(float len) { + this.len = len; + } + + @Override + public float getArea() { + return len * len; + } + } + + @Result public float[] outArray = new float[NUM]; + public Shape[] inShapeArray = new Shape[NUM]; + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + if (i % 2 == 0) { + inShapeArray[i] = new Circle(i + 1); + } else { + inShapeArray[i] = new Square(i + 1); + } + outArray[i] = -i; + } + } + + public void run(int gid) { + outArray[gid] = (inShapeArray[gid] instanceof Circle ? 1.0f : 2.0f); + } + + @Override + public void runTest() { + setupArrays(); + + dispatchMethodKernel(NUM); + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyCallTest.java --- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyCallTest.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyCallTest.java Sat Nov 09 21:34:07 2013 +0100 @@ -23,10 +23,15 @@ package com.oracle.graal.compiler.hsail.test; +import static com.oracle.graal.phases.GraalOptions.*; import static org.junit.Assume.*; import org.junit.*; +import com.oracle.graal.options.*; +import com.oracle.graal.options.OptionValue.OverrideScope; +import com.oracle.graal.phases.*; + /** * Unit test of NBody demo app. This version uses a call to the main routine which would normally be * too large to inline. @@ -37,10 +42,15 @@ StaticNBodyTest.run(inxyz, outxyz, invxyz, outvxyz, gid); } + public void before() { + } + @Test @Override - public void test() { - assumeTrue(aggressiveInliningEnabled() || canHandleHSAILMethodCalls()); - testGeneratedHsail(); + public void test() throws Exception { + try (OverrideScope s = OptionValue.override(InlineEverything, true, getOptionFromField(GraalOptions.class, "RemoveNeverExecutedCode"), false)) { + assumeTrue(aggressiveInliningEnabled() || canHandleHSAILMethodCalls()); + testGeneratedHsail(); + } } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyTest.java --- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyTest.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyTest.java Sat Nov 09 21:34:07 2013 +0100 @@ -96,7 +96,7 @@ } @Test - public void test() { + public void test() throws Exception { testGeneratedHsail(); } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StringContainsAcceptTest.java --- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StringContainsAcceptTest.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StringContainsAcceptTest.java Sat Nov 09 21:34:07 2013 +0100 @@ -24,6 +24,12 @@ package com.oracle.graal.compiler.hsail.test; import org.junit.Test; + +import com.oracle.graal.options.*; +import com.oracle.graal.options.OptionValue.*; +import com.oracle.graal.phases.*; + +import static com.oracle.graal.phases.GraalOptions.*; import static org.junit.Assume.*; /** @@ -50,8 +56,9 @@ @Test @Override public void test() { - assumeTrue(aggressiveInliningEnabled() || canHandleHSAILMethodCalls()); - testGeneratedHsail(); + try (OverrideScope s = OptionValue.override(InlineEverything, true, getOptionFromField(GraalOptions.class, "RemoveNeverExecutedCode"), false)) { + assumeTrue(aggressiveInliningEnabled() || canHandleHSAILMethodCalls()); + testGeneratedHsail(); + } } - } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Sat Nov 09 21:34:07 2013 +0100 @@ -414,7 +414,7 @@ private void emitIntegerTest(Value a, Value b) { - assert a.getKind().getStackKind() == Kind.Int || a.getKind() == Kind.Long; + assert a.getKind().isNumericInteger(); if (LIRValueUtil.isVariable(b)) { append(new PTXTestOp(load(b), loadNonConst(a), nextPredRegNum)); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Sat Nov 09 21:34:07 2013 +0100 @@ -267,7 +267,7 @@ } private void emitIntegerTest(Value a, Value b) { - assert a.getKind().getStackKind() == Kind.Int || a.getKind() == Kind.Long; + assert a.getKind().isNumericInteger(); if (LIRValueUtil.isVariable(b)) { append(new SPARCTestOp(load(b), loadNonConst(a))); } else { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Sat Nov 09 21:34:07 2013 +0100 @@ -209,12 +209,15 @@ HighTierContext highTierContext = new HighTierContext(providers, assumptions, cache, plan, optimisticOpts); suites.getHighTier().apply(graph, highTierContext); + graph.maybeCompress(); MidTierContext midTierContext = new MidTierContext(providers, assumptions, target, optimisticOpts); suites.getMidTier().apply(graph, midTierContext); + graph.maybeCompress(); LowTierContext lowTierContext = new LowTierContext(providers, assumptions, target); suites.getLowTier().apply(graph, lowTierContext); + graph.maybeCompress(); // we do not want to store statistics about OSR compilations because it may prevent inlining if (!graph.isOSR()) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Sat Nov 09 21:34:07 2013 +0100 @@ -54,6 +54,8 @@ public static final OptionValue DebugValueSummary = new OptionValue<>("Name"); @Option(help = "Omit reporting 0-value metrics") public static final OptionValue SuppressZeroDebugValues = new OptionValue<>(false); + @Option(help = "Report and reset metrics after bootstrapping") + public static final OptionValue ResetDebugValuesAfterBootstrap = new OptionValue<>(true); @Option(help = "Send Graal IR to dump handlers on error") public static final OptionValue DumpOnError = new OptionValue<>(false); @Option(help = "Enable expensive assertions") diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/IntervalWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/IntervalWalker.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/IntervalWalker.java Sat Nov 09 21:34:07 2013 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.compiler.alloc; -import static com.oracle.graal.phases.GraalOptions.*; - import com.oracle.graal.compiler.alloc.Interval.RegisterBinding; import com.oracle.graal.compiler.alloc.Interval.RegisterBindingLists; import com.oracle.graal.compiler.alloc.Interval.State; @@ -203,13 +201,17 @@ currentInterval.rewindRange(); } + int getTraceLevel() { + return allocator.getTraceLevel(); + } + void walkTo(int toOpId) { assert currentPosition <= toOpId : "can not walk backwards"; while (currentInterval != null) { boolean isActive = currentInterval.from() <= toOpId; int opId = isActive ? currentInterval.from() : toOpId; - if (TraceLinearScanLevel.getValue() >= 2 && !TTY.isSuppressed()) { + if (getTraceLevel() >= 2 && !TTY.isSuppressed()) { if (currentPosition < opId) { TTY.println(); TTY.println("walkTo(%d) *", opId); @@ -240,7 +242,7 @@ private void intervalMoved(Interval interval, State from, State to) { // intervalMoved() is called whenever an interval moves from one interval list to another. // In the implementation of this method it is prohibited to move the interval to any list. - if (TraceLinearScanLevel.getValue() >= 4 && !TTY.isSuppressed()) { + if (getTraceLevel() >= 4 && !TTY.isSuppressed()) { TTY.print(from.toString() + " to " + to.toString()); TTY.fillTo(23); TTY.out().println(interval.logString(allocator)); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Sat Nov 09 21:34:07 2013 +0100 @@ -26,7 +26,6 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.compiler.GraalDebugConfig.*; import static com.oracle.graal.lir.LIRValueUtil.*; -import static com.oracle.graal.phases.GraalOptions.*; import java.util.*; @@ -46,6 +45,7 @@ import com.oracle.graal.lir.LIRInstruction.ValueProcedure; import com.oracle.graal.lir.StandardOp.MoveOp; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.util.*; /** @@ -56,6 +56,13 @@ */ public final class LinearScan { + static class Options { + // @formatter:off + @Option(help = "The trace level for the linear scan register allocator") + public static final OptionValue TraceLinearScanLevel = new OptionValue<>(0); + // @formatter:on + } + final TargetDescription target; final LIR ir; final LIRGenerator gen; @@ -158,6 +165,8 @@ */ private final int firstVariableNumber; + private final int traceLevel; + public LinearScan(TargetDescription target, LIR ir, LIRGenerator gen, FrameMap frameMap) { this.target = target; this.ir = ir; @@ -170,6 +179,11 @@ this.firstVariableNumber = registers.length; this.variables = new ArrayList<>(ir.numVariables() * 3 / 2); this.blockData = new BlockMap<>(ir.cfg); + traceLevel = Options.TraceLinearScanLevel.getValue(); + } + + int getTraceLevel() { + return traceLevel; } public int getFirstLirInstructionId(Block block) { @@ -504,7 +518,7 @@ // called once before assignment of register numbers void eliminateSpillMoves() { - if (TraceLinearScanLevel.getValue() >= 3) { + if (getTraceLevel() >= 3) { TTY.println(" Eliminating unnecessary spill moves"); } @@ -538,7 +552,7 @@ if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) { // move target is a stack slot that is always correct, so eliminate // instruction - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult())); } instructions.set(j, null); // null-instructions are deleted by assignRegNum @@ -564,7 +578,7 @@ insertionBuffer.append(j + 1, ir.spillMoveFactory.createMove(toLocation, fromLocation)); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { StackSlot slot = interval.spillSlot(); TTY.println("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, slot, opId); } @@ -582,7 +596,7 @@ assert interval == Interval.EndMarker : "missed an interval"; } - private static void checkIntervals(Interval interval) { + private void checkIntervals(Interval interval) { Interval prev = null; Interval temp = interval; while (temp != Interval.EndMarker) { @@ -596,7 +610,7 @@ assert temp.spillDefinitionPos() >= temp.from() : "invalid order"; assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized"; - if (TraceLinearScanLevel.getValue() >= 4) { + if (traceLevel >= 4) { TTY.println("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos()); } @@ -698,7 +712,7 @@ int operandNum = operandNumber(operand); if (!liveKill.get(operandNum)) { liveGen.set(operandNum); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" Setting liveGen for operand %d at instruction %d", operandNum, op.id()); } } @@ -720,7 +734,7 @@ int operandNum = operandNumber(operand); if (!liveKill.get(operandNum)) { liveGen.set(operandNum); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" Setting liveGen for LIR opId %d, operand %d because of state for %s", op.id(), operandNum, op); } } @@ -763,7 +777,7 @@ blockData.get(block).liveIn = new BitSet(liveSize); blockData.get(block).liveOut = new BitSet(liveSize); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("liveGen B%d %s", block.getId(), blockData.get(block).liveGen); TTY.println("liveKill B%d %s", block.getId(), blockData.get(block).liveKill); } @@ -852,7 +866,7 @@ liveIn.or(blockData.get(block).liveGen); } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { traceLiveness(changeOccurredInBlock, iterationCount, block); } } @@ -974,7 +988,7 @@ if (!isProcessed(operand)) { return; } - if (TraceLinearScanLevel.getValue() >= 2 && kind == null) { + if (getTraceLevel() >= 2 && kind == null) { TTY.println(" use %s from %d to %d (%s)", operand, from, to, registerPriority.name()); } @@ -993,7 +1007,7 @@ if (!isProcessed(operand)) { return; } - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" temp %s tempPos %d (%s)", operand, tempPos, RegisterPriority.MustHaveRegister.name()); } @@ -1014,7 +1028,7 @@ if (!isProcessed(operand)) { return; } - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" def %s defPos %d (%s)", operand, defPos, registerPriority.name()); } @@ -1035,7 +1049,7 @@ // also add register priority for dead intervals interval.addRange(defPos, defPos + 1); interval.addUsePos(defPos, registerPriority); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println("Warning: def of operand %s at %d occurs without use", operand, defPos); } } @@ -1096,7 +1110,7 @@ assert blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block"; assert isVariable(move.getResult()) : "result of move must be a variable"; - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("found move from stack slot %s to %s", slot, move.getResult()); } } @@ -1126,7 +1140,7 @@ from.setLocationHint(to); } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber); } return registerHint; @@ -1159,7 +1173,7 @@ for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { assert live.get(operandNum) : "should not stop here otherwise"; AllocatableValue operand = operandFor(operandNum); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println("live in %s to %d", operand, blockTo + 2); } @@ -1187,7 +1201,7 @@ addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal); } } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("operation destroys all caller-save registers"); } } @@ -1438,7 +1452,7 @@ Interval result = interval.getSplitChildAtOpId(opId, mode, this); if (result != null) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("Split child at pos " + opId + " of interval " + interval.toString() + " is " + result.toString()); } return result; @@ -1492,7 +1506,7 @@ void resolveFindInsertPos(Block fromBlock, Block toBlock, MoveResolver moveResolver) { if (fromBlock.getSuccessorCount() <= 1) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("inserting moves at end of fromBlock B%d", fromBlock.getId()); } @@ -1506,7 +1520,7 @@ } } else { - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("inserting moves at beginning of toBlock B%d", toBlock.getId()); } @@ -1551,7 +1565,7 @@ // prevent optimization of two consecutive blocks if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) { - if (TraceLinearScanLevel.getValue() >= 3) { + if (getTraceLevel() >= 3) { TTY.println(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId()); } blockCompleted.set(block.getLinearScanNumber()); @@ -1578,7 +1592,7 @@ // check for duplicate edges between the same blocks (can happen with switch // blocks) if (!alreadyResolved.get(toBlock.getLinearScanNumber())) { - if (TraceLinearScanLevel.getValue() >= 3) { + if (getTraceLevel() >= 3) { TTY.println(" processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId()); } alreadyResolved.set(toBlock.getLinearScanNumber()); @@ -1657,7 +1671,7 @@ } void computeOopMap(IntervalWalker iw, LIRInstruction op, BitSet registerRefMap, BitSet frameRefMap) { - if (TraceLinearScanLevel.getValue() >= 3) { + if (getTraceLevel() >= 3) { TTY.println("creating oop map at opId %d", op.id()); } @@ -1866,7 +1880,7 @@ } void printIntervals(String label) { - if (TraceLinearScanLevel.getValue() >= 1) { + if (getTraceLevel() >= 1) { int i; TTY.println(); TTY.println(label); @@ -1896,27 +1910,27 @@ boolean verify() { // (check that all intervals have a correct register and that no registers are overwritten) - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" verifying intervals *"); } verifyIntervals(); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" verifying that no oops are in fixed intervals *"); } // verifyNoOopsInFixedIntervals(); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" verifying that unpinned constants are not alive across block boundaries"); } verifyConstants(); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" verifying register allocation *"); } verifyRegisters(); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" no errors found *"); } @@ -2068,7 +2082,7 @@ // visit all operands where the liveAtEdge bit is set for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("checking interval %d of block B%d", operandNum, block.getId()); } Value operand = operandFor(operandNum); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Sat Nov 09 21:34:07 2013 +0100 @@ -25,8 +25,6 @@ import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRValueUtil.*; -import static com.oracle.graal.phases.GraalOptions.*; - import java.util.*; import com.oracle.graal.api.code.*; @@ -295,7 +293,7 @@ int optimalSplitPos = -1; if (minSplitPos == maxSplitPos) { // trivial case, no optimization of split position possible - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" min-pos and max-pos are equal, no optimization possible"); } optimalSplitPos = minSplitPos; @@ -319,7 +317,7 @@ assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order"; if (minBlock == maxBlock) { // split position cannot be moved to block boundary : so split as late as possible - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" cannot move split pos to block boundary because minPos and maxPos are in same block"); } optimalSplitPos = maxSplitPos; @@ -331,14 +329,14 @@ // as mustHaveRegister) with a hole before each definition. When the register is // needed // for the second definition : an earlier reloading is unnecessary. - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" interval has hole just before maxSplitPos, so splitting at maxSplitPos"); } optimalSplitPos = maxSplitPos; } else { // seach optimal block boundary between minSplitPos and maxSplitPos - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId()); } @@ -347,7 +345,7 @@ // max-position : // then split before this loop int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, allocator.getLastLirInstructionId(minBlock) + 2); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" loop optimization: loop end found at pos %d", loopEndPos); } @@ -362,7 +360,7 @@ // of the interval (normally, only mustHaveRegister causes a reloading) Block loopBlock = allocator.blockForId(loopEndPos); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.getId(), maxBlock.getId(), loopBlock.getId()); } @@ -371,11 +369,11 @@ optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, allocator.getLastLirInstructionId(loopBlock) + 2); if (optimalSplitPos == allocator.getLastLirInstructionId(loopBlock) + 2) { optimalSplitPos = -1; - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" loop optimization not necessary"); } } else { - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" loop optimization successful"); } } @@ -389,7 +387,7 @@ } } } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" optimal split position: %d", optimalSplitPos); } @@ -401,13 +399,13 @@ // 1) the left part has already a location assigned // 2) the right part is sorted into to the unhandled-list void splitBeforeUsage(Interval interval, int minSplitPos, int maxSplitPos) { - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println("----- splitting interval: "); } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(interval.logString(allocator)); } - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" between %d and %d", minSplitPos, maxSplitPos); } @@ -425,7 +423,7 @@ if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) { // the split position would be just before the end of the interval // . no split at all necessary - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" no split necessary because optimal split position is at end of interval"); } return; @@ -440,7 +438,7 @@ optimalSplitPos = (optimalSplitPos - 1) | 1; } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" splitting at position %d", optimalSplitPos); } assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary"; @@ -453,10 +451,10 @@ assert splitPart.from() >= currentInterval.currentFrom() : "cannot append new interval before current walk position"; unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" split interval in two parts (insertMoveWhenActivated: %b)", moveNecessary); } - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.print(" "); TTY.println(interval.logString(allocator)); TTY.print(" "); @@ -474,7 +472,7 @@ int maxSplitPos = currentPosition; int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos) + 1, interval.from()); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.print("----- splitting and spilling interval: "); TTY.println(interval.logString(allocator)); TTY.println(" between %d and %d", minSplitPos, maxSplitPos); @@ -488,7 +486,7 @@ if (minSplitPos == interval.from()) { // the whole interval is never used, so spill it entirely to memory - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" spilling entire interval because split pos is at beginning of interval"); TTY.println(" use positions: " + interval.usePosList().size()); } @@ -507,7 +505,7 @@ if (isRegister(parent.location())) { if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) { // parent is never used, so kick it out of its assigned register - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" kicking out interval %d out of its register because it is never used", parent.operandNumber); } allocator.assignSpillSlot(parent); @@ -532,7 +530,7 @@ optimalSplitPos = (optimalSplitPos - 1) | 1; } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" splitting at position %d", optimalSplitPos); } assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary"; @@ -543,7 +541,7 @@ allocator.changeSpillState(spilledPart, optimalSplitPos); if (!allocator.isBlockBegin(optimalSplitPos)) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber); } insertMove(optimalSplitPos, interval, spilledPart); @@ -553,7 +551,7 @@ assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild"; spilledPart.makeCurrentSplitChild(); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println(" split interval in two parts"); TTY.print(" "); TTY.println(interval.logString(allocator)); @@ -602,7 +600,7 @@ } boolean allocFreeRegister(Interval interval) { - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println("trying to find free register for " + interval.logString(allocator)); } @@ -618,7 +616,7 @@ // (either as a fixed register or a normal allocated register in the past) // only intervals overlapping with cur are processed, non-overlapping invervals can be // ignored safely - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" state of registers:"); for (Register register : availableRegs) { int i = register.number; @@ -630,7 +628,7 @@ Interval locationHint = interval.locationHint(true); if (locationHint != null && locationHint.location() != null && isRegister(locationHint.location())) { hint = asRegister(locationHint.location()); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" hint register %d from interval %s", hint.number, locationHint.logString(allocator)); } } @@ -674,7 +672,7 @@ splitPos = usePos[reg.number]; interval.assignLocation(reg.asValue(interval.kind())); - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println("selected register %d", reg.number); } @@ -700,7 +698,7 @@ // Split an Interval and spill it to memory so that cur can be placed in a register void allocLockedRegister(Interval interval) { - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println("need to split and spill to get register for " + interval.logString(allocator)); } @@ -713,7 +711,7 @@ spillCollectActiveAny(); spillCollectInactiveAny(interval); - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" state of registers:"); for (Register reg : availableRegs) { int i = reg.number; @@ -746,7 +744,7 @@ if (reg == null || usePos[reg.number] <= firstUsage) { // the first use of cur is later than the spilling position -> spill cur - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, reg == null ? 0 : usePos[reg.number]); } @@ -765,7 +763,7 @@ int splitPos = blockPos[reg.number]; - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("decided to use register %d", reg.number); } assert splitPos > 0 : "invalid splitPos"; @@ -793,7 +791,7 @@ if (isOdd(pos)) { // the current instruction is a call that blocks all registers if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" free register cannot be available because all registers blocked by following call"); } @@ -885,11 +883,11 @@ Interval interval = currentInterval; boolean result = true; - if (TraceLinearScanLevel.getValue() >= 2) { + if (getTraceLevel() >= 2) { TTY.println("+++++ activating interval " + interval.logString(allocator)); } - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" splitParent: %s, insertMoveWhenActivated: %b", interval.splitParent().operandNumber, interval.insertMoveWhenActivated()); } @@ -898,7 +896,7 @@ // activating an interval that has a stack slot assigned . split it at first use // position // used for method parameters - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" interval has spill slot assigned (method parameter) . split it before first use"); } splitStackInterval(interval); @@ -908,7 +906,7 @@ if (interval.location() == null) { // interval has not assigned register . normal allocation // (this is the normal case for most intervals) - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println(" normal allocation of register"); } @@ -934,7 +932,7 @@ assert interval.isSplitChild(); assert interval.currentSplitChild() != null; assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval"; - if (TraceLinearScanLevel.getValue() >= 4) { + if (getTraceLevel() >= 4) { TTY.println("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Sat Nov 09 21:34:07 2013 +0100 @@ -23,8 +23,6 @@ package com.oracle.graal.compiler.alloc; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.phases.GraalOptions.*; - import java.util.*; import com.oracle.graal.api.code.*; @@ -201,7 +199,7 @@ insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr)); - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.println("MoveResolver: inserted move from %d (%s) to %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location()); } } @@ -213,7 +211,7 @@ AllocatableValue toOpr = toInterval.operand; insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr)); - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.print("MoveResolver: inserted move from constant %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location()); } } @@ -285,7 +283,7 @@ } spillInterval.assignLocation(spillSlot); - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.println("created new Interval %s for spilling", spillInterval.operand); } @@ -327,7 +325,7 @@ } void addMapping(Interval fromInterval, Interval toInterval) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.println("MoveResolver: adding mapping from interval %d (%s) to interval %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location()); } @@ -339,7 +337,7 @@ } void addMapping(Value fromOpr, Interval toInterval) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.println("MoveResolver: adding mapping from %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location()); } assert isConstant(fromOpr) : "only for constants"; diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Sat Nov 09 21:34:07 2013 +0100 @@ -23,8 +23,6 @@ package com.oracle.graal.compiler.alloc; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.phases.GraalOptions.*; - import java.util.*; import com.oracle.graal.api.code.*; @@ -92,7 +90,7 @@ } private void processBlock(Block block) { - if (TraceLinearScanLevel.getValue() >= 2) { + if (allocator.getTraceLevel() >= 2) { TTY.println(); TTY.println("processBlock B%d", block.getId()); } @@ -100,7 +98,7 @@ // must copy state because it is modified Interval[] inputState = copy(stateForBlock(block)); - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.println("Input-State of intervals:"); TTY.print(" "); for (int i = 0; i < stateSize(); i++) { @@ -142,7 +140,7 @@ savedStateCorrect = false; savedState[i] = null; - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.println("processSuccessor B%d: invalidating slot %d", block.getId(), i); } } @@ -151,12 +149,12 @@ if (savedStateCorrect) { // already processed block with correct inputState - if (TraceLinearScanLevel.getValue() >= 2) { + if (allocator.getTraceLevel() >= 2) { TTY.println("processSuccessor B%d: previous visit already correct", block.getId()); } } else { // must re-visit this block - if (TraceLinearScanLevel.getValue() >= 2) { + if (allocator.getTraceLevel() >= 2) { TTY.println("processSuccessor B%d: must re-visit because input state changed", block.getId()); } addToWorkList(block); @@ -164,7 +162,7 @@ } else { // block was not processed before, so set initial inputState - if (TraceLinearScanLevel.getValue() >= 2) { + if (allocator.getTraceLevel() >= 2) { TTY.println("processSuccessor B%d: initial visit", block.getId()); } @@ -177,16 +175,16 @@ return inputState.clone(); } - static void statePut(Interval[] inputState, Value location, Interval interval) { + static void statePut(Interval[] inputState, Value location, Interval interval, int traceLevel) { if (location != null && isRegister(location)) { Register reg = asRegister(location); int regNum = reg.number; if (interval != null) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (traceLevel >= 4) { TTY.println(" %s = %s", reg, interval.operand); } } else if (inputState[regNum] != null) { - if (TraceLinearScanLevel.getValue() >= 4) { + if (traceLevel >= 4) { TTY.println(" %s = null", reg); } } @@ -209,7 +207,7 @@ for (int i = 0; i < ops.size(); i++) { final LIRInstruction op = ops.get(i); - if (TraceLinearScanLevel.getValue() >= 4) { + if (allocator.getTraceLevel() >= 4) { TTY.println(op.toStringWithIdPrefix()); } @@ -239,7 +237,7 @@ interval = interval.getSplitChildAtOpId(op.id(), mode, allocator); } - statePut(inputState, interval.location(), interval.splitParent()); + statePut(inputState, interval.location(), interval.splitParent(), allocator.getTraceLevel()); } return operand; } @@ -250,7 +248,7 @@ // invalidate all caller save registers at calls if (op.destroysCallerSavedRegisters()) { for (Register r : allocator.frameMap.registerConfig.getCallerSaveRegisters()) { - statePut(inputState, r.asValue(), null); + statePut(inputState, r.asValue(), null, allocator.getTraceLevel()); } } op.forEachAlive(useProc); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Sat Nov 09 21:34:07 2013 +0100 @@ -39,6 +39,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.FallThroughOp; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.StandardOp.LabelOp; import com.oracle.graal.nodes.*; @@ -49,6 +50,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.util.*; /** @@ -56,6 +58,15 @@ */ public abstract class LIRGenerator implements LIRGeneratorTool { + public static class Options { + // @formatter:off + @Option(help = "Print HIR along side LIR as the latter is generated") + public static final OptionValue PrintIRWithLIR = new OptionValue<>(false); + @Option(help = "The trace level for the LIR generator") + public static final OptionValue TraceLIRGeneratorLevel = new OptionValue<>(0); + // @formatter:on + } + public final FrameMap frameMap; public final NodeMap nodeOperands; public final LIR lir; @@ -67,6 +78,8 @@ protected final DebugInfoBuilder debugInfoBuilder; protected Block currentBlock; + private final int traceLevel; + private final boolean printIRWithLIR; /** * Maps constants the variables within the scope of a single block to avoid loading a constant @@ -106,6 +119,8 @@ this.nodeOperands = graph.createNodeMap(); this.lir = lir; this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands); + this.traceLevel = Options.TraceLIRGeneratorLevel.getValue(); + this.printIRWithLIR = Options.PrintIRWithLIR.getValue(); } @SuppressWarnings("hiding") @@ -316,7 +331,7 @@ } public void append(LIRInstruction op) { - if (PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { + if (printIRWithLIR && !TTY.isSuppressed()) { if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { lastInstructionPrinted = currentInstruction; InstructionPrinter ip = new InstructionPrinter(TTY.out()); @@ -330,7 +345,7 @@ } public void doBlock(Block block) { - if (PrintIRWithLIR.getValue()) { + if (printIRWithLIR) { TTY.print(block.toString()); } @@ -343,7 +358,7 @@ append(new LabelOp(new Label(block.getId()), block.isAligned())); - if (TraceLIRGeneratorLevel.getValue() >= 1) { + if (traceLevel >= 1) { TTY.println("BEGIN Generating LIR for block B" + block.getId()); } @@ -357,7 +372,7 @@ List nodes = lir.nodesFor(block); for (int i = 0; i < nodes.size(); i++) { Node instr = nodes.get(i); - if (TraceLIRGeneratorLevel.getValue() >= 3) { + if (traceLevel >= 3) { TTY.println("LIRGen for " + instr); } if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) { @@ -387,13 +402,13 @@ emitJump(getLIRBlock((FixedNode) successors.first())); } - if (TraceLIRGeneratorLevel.getValue() >= 1) { + if (traceLevel >= 1) { TTY.println("END Generating LIR for block B" + block.getId()); } currentBlock = null; - if (PrintIRWithLIR.getValue()) { + if (printIRWithLIR) { TTY.println(); } } @@ -412,11 +427,16 @@ return false; } LIRInstruction lirInstruction = instructions.get(instructions.size() - 1); - return lirInstruction instanceof StandardOp.JumpOp; + if (lirInstruction instanceof StandardOp.JumpOp) { + return true; + } else if (lirInstruction instanceof FallThroughOp) { + return ((FallThroughOp) lirInstruction).fallThroughTarget() != null; + } + return false; } private void doRoot(ValueNode instr) { - if (TraceLIRGeneratorLevel.getValue() >= 2) { + if (traceLevel >= 2) { TTY.println("Emitting LIR for instruction " + instr); } currentInstruction = instr; @@ -497,7 +517,7 @@ } private void moveToPhi(MergeNode merge, AbstractEndNode pred) { - if (TraceLIRGeneratorLevel.getValue() >= 1) { + if (traceLevel >= 1) { TTY.println("MOVE TO PHI from " + pred + " to " + merge); } PhiResolver resolver = new PhiResolver(this); @@ -753,7 +773,7 @@ } } - private void emitSequentialSwitch(final SwitchNode x, Variable key, LabelRef defaultTarget) { + protected void emitSequentialSwitch(final SwitchNode x, Variable key, LabelRef defaultTarget) { int keyCount = x.keyCount(); Integer[] indexes = Util.createSortedPermutation(keyCount, new Comparator() { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValueMap.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValueMap.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValueMap.java Sat Nov 09 21:34:07 2013 +0100 @@ -55,6 +55,17 @@ } } + public void reset() { + if (values != null) { + Arrays.fill(values, 0L); + } + if (children != null) { + for (DebugValueMap child : children) { + child.reset(); + } + } + } + private void ensureSize(int index) { if (values == null) { values = new long[index + 1]; diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Sat Nov 09 21:34:07 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.GraphEvent.NodeEvent; import com.oracle.graal.graph.Node.ValueNumberable; import com.oracle.graal.graph.iterators.*; @@ -37,7 +38,15 @@ private static final boolean TIME_TRAVEL = false; - private final ArrayList nodes; + /** + * The set of nodes in the graph, ordered by {@linkplain #register(Node) registration} time. + */ + private Node[] nodes; + + /** + * The number of valid entries in {@link #nodes}. + */ + private int nodesSize; /** * Records the modification count for nodes. This is only used in assertions. @@ -53,9 +62,15 @@ // they contain the first and last pointer to a linked list of all nodes with this type. private final ArrayList nodeCacheFirst; private final ArrayList nodeCacheLast; - private int deletedNodeCount; + private int nodesDeletedSinceLastCompression; + private int nodesDeletedBeforeLastCompression; private GraphEventLog eventLog; + /** + * The number of times this graph has been compressed. + */ + int compressions; + NodeChangedListener inputChangedListener; NodeChangedListener usagesDroppedToZeroListener; private final HashMap cachedNodes = new HashMap<>(); @@ -110,19 +125,21 @@ return enabled; } + private static final int INITIAL_NODES_SIZE = 32; + /** * Creates an empty Graph with a given name. * * @param name the name of the graph, used for debugging purposes */ public Graph(String name) { - nodes = new ArrayList<>(32); + nodes = new Node[INITIAL_NODES_SIZE]; nodeCacheFirst = new ArrayList<>(NodeClass.cacheSize()); nodeCacheLast = new ArrayList<>(NodeClass.cacheSize()); this.name = name; if (MODIFICATION_COUNTS_ENABLED) { - nodeModCounts = new int[nodes.size()]; - nodeUsageModCounts = new int[nodes.size()]; + nodeModCounts = new int[INITIAL_NODES_SIZE]; + nodeUsageModCounts = new int[INITIAL_NODES_SIZE]; } } @@ -204,16 +221,31 @@ * @return the number of live nodes in this graph */ public int getNodeCount() { - return nodes.size() - getDeletedNodeCount(); + return nodesSize - getNodesDeletedSinceLastCompression(); + } + + /** + * Gets the number of times this graph has been {@linkplain #maybeCompress() compressed}. Node + * identifiers are only stable between compressions. To ensure this constraint is observed, any + * entity relying upon stable node identifiers should use {@link NodeIdAccessor}. + */ + public int getCompressions() { + return compressions; } /** - * Gets the number of node which have been deleted from this graph. - * - * @return the number of node which have been deleted from this graph + * Gets the number of nodes which have been deleted from this graph since it was last + * {@linkplain #maybeCompress() compressed}. */ - public int getDeletedNodeCount() { - return deletedNodeCount; + public int getNodesDeletedSinceLastCompression() { + return nodesDeletedSinceLastCompression; + } + + /** + * Gets the total number of nodes which have been deleted from this graph. + */ + public int getTotalNodesDeleted() { + return nodesDeletedSinceLastCompression + nodesDeletedBeforeLastCompression; } /** @@ -394,15 +426,56 @@ } } - public boolean isNew(int mark, Node node) { - return node.id >= mark; + public boolean isNew(Mark mark, Node node) { + return node.id >= mark.getValue(); } /** - * Gets a mark that can be used with {@link #getNewNodes(int)}. + * A snapshot of the {@linkplain Graph#getNodeCount() live node count} in a graph. */ - public int getMark() { - return nodeIdCount(); + public static class Mark extends NodeIdAccessor { + private final int value; + + Mark(Graph graph) { + super(graph); + this.value = graph.nodeIdCount(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Mark) { + Mark other = (Mark) obj; + return other.getValue() == getValue() && other.getGraph() == getGraph(); + } + return false; + } + + @Override + public int hashCode() { + return value ^ (epoch + 11); + } + + /** + * Determines if this mark is positioned at the first live node in the graph. + */ + public boolean isStart() { + return value == 0; + } + + /** + * Gets the {@linkplain Graph#getNodeCount() live node count} of the associated graph when + * this object was created. + */ + int getValue() { + return value; + } + } + + /** + * Gets a mark that can be used with {@link #getNewNodes}. + */ + public Mark getMark() { + return new Mark(this); } private class NodeIterator implements Iterator { @@ -419,22 +492,22 @@ } private void forward() { - if (index < nodes.size()) { + if (index < nodesSize) { do { index++; - } while (index < nodes.size() && nodes.get(index) == null); + } while (index < nodesSize && nodes[index] == null); } } @Override public boolean hasNext() { checkForDeletedNode(); - return index < nodes.size(); + return index < nodesSize; } private void checkForDeletedNode() { - if (index < nodes.size()) { - while (index < nodes.size() && nodes.get(index) == null) { + if (index < nodesSize) { + while (index < nodesSize && nodes[index] == null) { index++; } } @@ -443,7 +516,7 @@ @Override public Node next() { try { - return nodes.get(index); + return nodes[index]; } finally { forward(); } @@ -459,8 +532,8 @@ * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#getMark() * mark}. */ - public NodeIterable getNewNodes(int mark) { - final int index = mark; + public NodeIterable getNewNodes(Mark mark) { + final int index = mark.getValue(); return new AbstractNodeIterable() { @Override @@ -493,6 +566,55 @@ private static final Node PLACE_HOLDER = new Node() { }; + /** + * When the percent of live nodes in {@link #nodes} fall below this number, a call to + * {@link #maybeCompress()} will actually do compression. + */ + public static final int COMPRESSION_THRESHOLD = Integer.getInteger("graal.graphCompressionThreshold", 70); + + private static final DebugMetric GraphCompressions = Debug.metric("GraphCompressions"); + + /** + * If the {@linkplain #COMPRESSION_THRESHOLD compression threshold} is met, the list of nodes is + * compressed such that all non-null entries precede all null entries while preserving the + * ordering between the nodes within the list. + */ + public boolean maybeCompress() { + if (Debug.isEnabled()) { + return false; + } + int liveNodeCount = getNodeCount(); + int liveNodePercent = liveNodeCount * 100 / nodesSize; + if (COMPRESSION_THRESHOLD == 0 || liveNodePercent >= COMPRESSION_THRESHOLD) { + return false; + } + GraphCompressions.increment(); + int nextId = 0; + for (int i = 0; nextId < liveNodeCount; i++) { + Node n = nodes[i]; + if (n != null) { + assert n.id == i; + if (i != nextId) { + assert n.id > nextId; + n.id = nextId; + nodes[nextId] = n; + nodes[i] = null; + } + nextId++; + } + } + if (MODIFICATION_COUNTS_ENABLED) { + // This will cause any current iteration to fail with an assertion + Arrays.fill(nodeModCounts, 0); + Arrays.fill(nodeUsageModCounts, 0); + } + nodesSize = nextId; + compressions++; + nodesDeletedBeforeLastCompression += nodesDeletedSinceLastCompression; + nodesDeletedSinceLastCompression = 0; + return true; + } + private class TypedNodeIterator implements Iterator { private final int[] ids; @@ -656,8 +778,12 @@ void register(Node node) { assert !node.isExternal(); assert node.id() == Node.INITIAL_ID; - int id = nodes.size(); - nodes.add(id, node); + if (nodes.length == nodesSize) { + nodes = Arrays.copyOf(nodes, (nodesSize * 2) + 1); + } + int id = nodesSize; + nodes[id] = node; + nodesSize++; int nodeClassId = node.getNodeClass().iterableId(); if (nodeClassId != NodeClass.NOT_ITERABLE) { @@ -704,8 +830,8 @@ void unregister(Node node) { assert !node.isDeleted() : "cannot delete a node twice! node=" + node; logNodeDeleted(node); - nodes.set(node.id(), null); - deletedNodeCount++; + nodes[node.id] = null; + nodesDeletedSinceLastCompression++; // nodes aren't removed from the type cache here - they will be removed during iteration } @@ -728,7 +854,7 @@ } Node getNode(int i) { - return nodes.get(i); + return nodes[i]; } /** @@ -737,7 +863,7 @@ * @return the number of node ids generated so far */ int nodeIdCount() { - return nodes.size(); + return nodesSize; } /** diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Sat Nov 09 21:34:07 2013 +0100 @@ -152,7 +152,7 @@ this.id = INITIAL_ID; } - protected int id() { + int id() { return id; } @@ -745,12 +745,12 @@ } if (recordsUsages()) { for (Node usage : usages()) { - assertFalse(usage.isDeleted(), "usage must never be deleted"); + assertFalse(usage.isDeleted(), "usage %s must never be deleted", usage); assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage); } } if (predecessor != null) { - assertFalse(predecessor.isDeleted(), "predecessor must never be deleted"); + assertFalse(predecessor.isDeleted(), "predecessor %s must never be deleted", predecessor); assertTrue(predecessor.successors().contains(this), "missing successor in predecessor %s", predecessor); } return true; diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Sat Nov 09 21:34:07 2013 +0100 @@ -30,8 +30,8 @@ private final boolean autoGrow; private final BitSet bitMap; - private final Graph graph; private int nodeCount; + private final NodeIdAccessor nodeIdAccessor; public NodeBitMap(Graph graph) { this(graph, false); @@ -42,14 +42,14 @@ } private NodeBitMap(Graph graph, boolean autoGrow, int nodeCount, BitSet bits) { - this.graph = graph; + this.nodeIdAccessor = new NodeIdAccessor(graph); this.autoGrow = autoGrow; this.nodeCount = nodeCount; bitMap = bits; } public Graph graph() { - return graph; + return nodeIdAccessor.getGraph(); } public void setUnion(NodeBitMap other) { @@ -70,11 +70,11 @@ } public boolean isMarked(Node node) { - return bitMap.get(node.id()); + return bitMap.get(nodeIdAccessor.getNodeId(node)); } public boolean isNew(Node node) { - return node.id() >= nodeCount; + return nodeIdAccessor.getNodeId(node) >= nodeCount; } public void mark(Node node) { @@ -82,7 +82,7 @@ grow(); } assert check(node); - bitMap.set(node.id()); + bitMap.set(nodeIdAccessor.getNodeId(node)); } public void clear(Node node) { @@ -90,7 +90,7 @@ return; } assert check(node); - bitMap.clear(node.id()); + bitMap.clear(nodeIdAccessor.getNodeId(node)); } public void clearAll() { @@ -98,20 +98,20 @@ } public void intersect(NodeBitMap other) { - assert graph == other.graph; + assert graph() == other.graph(); bitMap.and(other.bitMap); } public void grow(Node node) { - nodeCount = Math.max(nodeCount, node.id() + 1); + nodeCount = Math.max(nodeCount, nodeIdAccessor.getNodeId(node) + 1); } public void grow() { - nodeCount = Math.max(nodeCount, graph.nodeIdCount()); + nodeCount = Math.max(nodeCount, graph().nodeIdCount()); } private boolean check(Node node) { - assert node.graph() == graph : "this node is not part of the graph"; + assert node.graph() == graph() : "this node is not part of the graph"; assert !isNew(node) : "node was added to the graph after creating the node bitmap: " + node; assert node.isAlive() : "node is deleted!"; return true; @@ -180,7 +180,7 @@ } public NodeBitMap copy() { - return new NodeBitMap(graph, autoGrow, nodeCount, (BitSet) bitMap.clone()); + return new NodeBitMap(graph(), autoGrow, nodeCount, (BitSet) bitMap.clone()); } @Override diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Sat Nov 09 21:34:07 2013 +0100 @@ -677,6 +677,32 @@ } } + private static int deepHashCode0(Object o) { + if (o instanceof Object[]) { + return Arrays.deepHashCode((Object[]) o); + } else if (o instanceof byte[]) { + return Arrays.hashCode((byte[]) o); + } else if (o instanceof short[]) { + return Arrays.hashCode((short[]) o); + } else if (o instanceof int[]) { + return Arrays.hashCode((int[]) o); + } else if (o instanceof long[]) { + return Arrays.hashCode((long[]) o); + } else if (o instanceof char[]) { + return Arrays.hashCode((char[]) o); + } else if (o instanceof float[]) { + return Arrays.hashCode((float[]) o); + } else if (o instanceof double[]) { + return Arrays.hashCode((double[]) o); + } else if (o instanceof boolean[]) { + return Arrays.hashCode((boolean[]) o); + } else if (o != null) { + return o.hashCode(); + } else { + return 0; + } + } + public int valueNumber(Node n) { int number = 0; if (canGVN) { @@ -695,16 +721,28 @@ if (booleanValue) { number += 7; } + } else if (type == Float.TYPE) { + float floatValue = unsafe.getFloat(n, dataOffsets[i]); + number += Float.floatToRawIntBits(floatValue); + } else if (type == Double.TYPE) { + double doubleValue = unsafe.getDouble(n, dataOffsets[i]); + long longValue = Double.doubleToRawLongBits(doubleValue); + number += longValue ^ (longValue >>> 32); + } else if (type == Short.TYPE) { + short shortValue = unsafe.getShort(n, dataOffsets[i]); + number += shortValue; + } else if (type == Character.TYPE) { + char charValue = unsafe.getChar(n, dataOffsets[i]); + number += charValue; + } else if (type == Byte.TYPE) { + byte byteValue = unsafe.getByte(n, dataOffsets[i]); + number += byteValue; } else { - assert false; + assert false : "unhandled property type: " + type; } } else { Object o = unsafe.getObject(n, dataOffsets[i]); - if (o instanceof Object[]) { - number += Arrays.deepHashCode((Object[]) o); - } else if (o != null) { - number += o.hashCode(); - } + number += deepHashCode0(o); } number *= 13; } @@ -733,6 +771,12 @@ value = unsafe.getFloat(node, dataOffsets[i]); } else if (type == Double.TYPE) { value = unsafe.getDouble(node, dataOffsets[i]); + } else if (type == Short.TYPE) { + value = unsafe.getShort(node, dataOffsets[i]); + } else if (type == Character.TYPE) { + value = unsafe.getChar(node, dataOffsets[i]); + } else if (type == Byte.TYPE) { + value = unsafe.getByte(node, dataOffsets[i]); } else { assert false : "unhandled property type: " + type; } @@ -743,6 +787,33 @@ } } + private static boolean deepEquals0(Object e1, Object e2) { + assert e1 != null; + boolean eq; + if (e1 instanceof Object[] && e2 instanceof Object[]) { + eq = Arrays.deepEquals((Object[]) e1, (Object[]) e2); + } else if (e1 instanceof byte[] && e2 instanceof byte[]) { + eq = Arrays.equals((byte[]) e1, (byte[]) e2); + } else if (e1 instanceof short[] && e2 instanceof short[]) { + eq = Arrays.equals((short[]) e1, (short[]) e2); + } else if (e1 instanceof int[] && e2 instanceof int[]) { + eq = Arrays.equals((int[]) e1, (int[]) e2); + } else if (e1 instanceof long[] && e2 instanceof long[]) { + eq = Arrays.equals((long[]) e1, (long[]) e2); + } else if (e1 instanceof char[] && e2 instanceof char[]) { + eq = Arrays.equals((char[]) e1, (char[]) e2); + } else if (e1 instanceof float[] && e2 instanceof float[]) { + eq = Arrays.equals((float[]) e1, (float[]) e2); + } else if (e1 instanceof double[] && e2 instanceof double[]) { + eq = Arrays.equals((double[]) e1, (double[]) e2); + } else if (e1 instanceof boolean[] && e2 instanceof boolean[]) { + eq = Arrays.equals((boolean[]) e1, (boolean[]) e2); + } else { + eq = e1.equals(e2); + } + return eq; + } + public boolean valueEqual(Node a, Node b) { if (!canGVN || a.getClass() != b.getClass()) { return a == b; @@ -768,12 +839,36 @@ if (aLong != bLong) { return false; } + } else if (type == Float.TYPE) { + float aFloat = unsafe.getFloat(a, dataOffsets[i]); + float bFloat = unsafe.getFloat(b, dataOffsets[i]); + if (aFloat != bFloat) { + return false; + } } else if (type == Double.TYPE) { double aDouble = unsafe.getDouble(a, dataOffsets[i]); double bDouble = unsafe.getDouble(b, dataOffsets[i]); if (aDouble != bDouble) { return false; } + } else if (type == Short.TYPE) { + short aShort = unsafe.getShort(a, dataOffsets[i]); + short bShort = unsafe.getShort(b, dataOffsets[i]); + if (aShort != bShort) { + return false; + } + } else if (type == Character.TYPE) { + char aChar = unsafe.getChar(a, dataOffsets[i]); + char bChar = unsafe.getChar(b, dataOffsets[i]); + if (aChar != bChar) { + return false; + } + } else if (type == Byte.TYPE) { + byte aByte = unsafe.getByte(a, dataOffsets[i]); + byte bByte = unsafe.getByte(b, dataOffsets[i]); + if (aByte != bByte) { + return false; + } } else { assert false : "unhandled type: " + type; } @@ -782,14 +877,8 @@ Object objectB = unsafe.getObject(b, dataOffsets[i]); if (objectA != objectB) { if (objectA != null && objectB != null) { - if (objectA instanceof Object[] && objectB instanceof Object[]) { - if (!Arrays.deepEquals((Object[]) objectA, (Object[]) objectB)) { - return false; - } - } else { - if (!(objectA.equals(objectB))) { - return false; - } + if (!deepEquals0(objectA, objectB)) { + return false; } } else { return false; @@ -1271,7 +1360,14 @@ } static Map addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable nodes, final DuplicationReplacement replacements) { - final Map newNodes = (estimatedNodeCount > (oldGraph.getNodeCount() + oldGraph.getDeletedNodeCount() >> 4)) ? new NodeNodeMap(oldGraph) : new IdentityHashMap(); + final Map newNodes; + if (estimatedNodeCount > (oldGraph.getNodeCount() + oldGraph.getNodesDeletedSinceLastCompression() >> 4)) { + // Use dense map + newNodes = new NodeNodeMap(oldGraph); + } else { + // Use sparse map + newNodes = new IdentityHashMap<>(); + } createNodeDuplicates(graph, nodes, replacements, newNodes); InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeIdAccessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeIdAccessor.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,63 @@ +/* + * 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.graph; + +/** + * An entity that depends upon {@linkplain Graph#maybeCompress() stable} node identifiers. + */ +class NodeIdAccessor { + final Graph graph; + final int epoch; + + public NodeIdAccessor(Graph graph) { + this.graph = graph; + this.epoch = graph.compressions; + } + + Graph getGraph() { + return graph; + } + + /** + * Verifies that node identifiers have not changed since this object was created. + * + * @return true if the check succeeds + * @throws VerificationError if the check fails + */ + public boolean verifyIdsAreStable() { + int compressions = graph.compressions - epoch; + if (compressions != 0) { + throw new VerificationError("accessing node id in %s across %d graph compression%s", graph, compressions, compressions == 1 ? "" : "s"); + } + return true; + } + + /** + * Gets the identifier for a node. If assertions are enabled, this method asserts that the + * identifier is stable. + */ + public int getNodeId(Node node) { + assert verifyIdsAreStable(); + return node.id(); + } +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Sat Nov 09 21:34:07 2013 +0100 @@ -26,9 +26,8 @@ import java.util.*; import java.util.Map.Entry; -public class NodeMap { +public class NodeMap extends NodeIdAccessor { - private final Graph graph; private final boolean autogrow; protected Object[] values; @@ -37,13 +36,13 @@ } public NodeMap(Graph graph, boolean autogrow) { - this.graph = graph; + super(graph); this.values = new Object[graph.nodeIdCount()]; this.autogrow = autogrow; } public NodeMap(NodeMap copyFrom) { - this.graph = copyFrom.graph; + super(copyFrom.graph); this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length); this.autogrow = copyFrom.autogrow; } @@ -51,7 +50,7 @@ @SuppressWarnings("unchecked") public T get(Node node) { check(node); - return (T) values[node.id()]; + return (T) values[getNodeId(node)]; } public boolean isEmpty() { @@ -83,7 +82,7 @@ public void set(Node node, T value) { check(node); - values[node.id()] = value; + values[getNodeId(node)] = value; } public int size() { @@ -91,7 +90,7 @@ } public boolean isNew(Node node) { - return node.id() >= size(); + return getNodeId(node) >= size(); } public void grow() { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Sat Nov 09 21:34:07 2013 +0100 @@ -406,7 +406,7 @@ @Override public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { - moveDeoptimizationActionAndReasonToThread(getMetaAccess().encodeDeoptActionAndReason(action, reason)); + moveDeoptimizationActionAndReasonToThread(getMetaAccess().encodeDeoptActionAndReason(action, reason, (short) 0)); append(new AMD64HotSpotDeoptimizeCallerOp()); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Sat Nov 09 21:34:07 2013 +0100 @@ -46,6 +46,30 @@ this.config = config; } + private int getLogMinObjectAlignment() { + return config.logMinObjAlignment(); + } + + private int getNarrowOopShift() { + return config.narrowOopShift; + } + + private long getNarrowOopBase() { + return config.narrowOopBase; + } + + private int getLogKlassAlignment() { + return config.logKlassAlignment; + } + + private int getNarrowKlassShift() { + return config.narrowKlassShift; + } + + private long getNarrowKlassBase() { + return config.narrowKlassBase; + } + private static boolean isCompressCandidate(DeoptimizingNode access) { return access != null && ((HeapAccess) access).isCompressible(); } @@ -56,9 +80,12 @@ Variable result = newVariable(kind); LIRFrameState state = access != null ? state(access) : null; assert access == null || access instanceof HeapAccess; - if (config.useCompressedOops && isCompressCandidate(access)) { + if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) { Variable scratch = newVariable(Kind.Long); - append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, config.narrowOopBase, config.narrowOopShift, config.logMinObjAlignment())); + append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment())); + } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) { + Variable scratch = newVariable(Kind.Long); + append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment())); } else { append(new LoadOp(kind, result, loadAddress, state)); } @@ -70,9 +97,12 @@ HSAILAddressValue storeAddress = asAddressValue(address); LIRFrameState state = access != null ? state(access) : null; Variable input = load(inputVal); - if (config.useCompressedOops && isCompressCandidate(access)) { + if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) { Variable scratch = newVariable(Kind.Long); - append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, config.narrowOopBase, config.narrowOopShift, config.logMinObjAlignment())); + append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment())); + } else if (isCompressCandidate(access) && config.useCompressedClassPointers && kind == Kind.Long) { + Variable scratch = newVariable(Kind.Long); + append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, getNarrowKlassBase(), getNarrowKlassShift(), getLogKlassAlignment())); } else { append(new StoreOp(kind, storeAddress, input, state)); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Sat Nov 09 21:34:07 2013 +0100 @@ -207,7 +207,7 @@ @Override public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { - moveDeoptimizationActionAndReasonToThread(getMetaAccess().encodeDeoptActionAndReason(action, reason)); + moveDeoptimizationActionAndReasonToThread(getMetaAccess().encodeDeoptActionAndReason(action, reason, (short) 0)); append(new SPARCHotSpotDeoptimizeCallerOp()); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Sat Nov 09 21:34:07 2013 +0100 @@ -323,6 +323,9 @@ } } while ((System.currentTimeMillis() - startTime) <= TimedBootstrap.getValue()); + if (ResetDebugValuesAfterBootstrap.getValue()) { + printDebugValues("bootstrap", true); + } phaseTransition("bootstrap"); bootstrapRunning = false; @@ -368,53 +371,7 @@ CompilationTask.withinEnqueue.set(Boolean.FALSE); } - if (Debug.isEnabled() && areMetricsOrTimersEnabled()) { - List topLevelMaps = DebugValueMap.getTopLevelMaps(); - List debugValues = KeyRegistry.getDebugValues(); - if (debugValues.size() > 0) { - ArrayList sortedValues = new ArrayList<>(debugValues); - Collections.sort(sortedValues); - - String summary = DebugValueSummary.getValue(); - if (summary == null) { - summary = "Complete"; - } - switch (summary) { - case "Name": - printSummary(topLevelMaps, sortedValues); - break; - case "Partial": { - DebugValueMap globalMap = new DebugValueMap("Global"); - for (DebugValueMap map : topLevelMaps) { - flattenChildren(map, globalMap); - } - globalMap.normalize(); - printMap(new DebugValueScope(null, globalMap), sortedValues); - break; - } - case "Complete": { - DebugValueMap globalMap = new DebugValueMap("Global"); - for (DebugValueMap map : topLevelMaps) { - globalMap.addChild(map); - } - globalMap.group(); - globalMap.normalize(); - printMap(new DebugValueScope(null, globalMap), sortedValues); - break; - } - case "Thread": - for (DebugValueMap map : topLevelMaps) { - TTY.println("Showing the results for thread: " + map.getName()); - map.group(); - map.normalize(); - printMap(new DebugValueScope(null, map), sortedValues); - } - break; - default: - throw new GraalInternalError("Unknown summary type: %s", summary); - } - } - } + printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false); phaseTransition("final"); if (runtime.getConfig().ciTime) { @@ -426,6 +383,79 @@ BenchmarkCounters.shutdown(runtime.getCompilerToVM(), compilerStartTime); } + private void printDebugValues(String phase, boolean reset) throws GraalInternalError { + if (Debug.isEnabled() && areMetricsOrTimersEnabled()) { + TTY.println(); + if (phase != null) { + TTY.println(""); + } else { + TTY.println(""); + } + List topLevelMaps = DebugValueMap.getTopLevelMaps(); + List debugValues = KeyRegistry.getDebugValues(); + if (debugValues.size() > 0) { + try { + ArrayList sortedValues = new ArrayList<>(debugValues); + Collections.sort(sortedValues); + + String summary = DebugValueSummary.getValue(); + if (summary == null) { + summary = "Complete"; + } + switch (summary) { + case "Name": + printSummary(topLevelMaps, sortedValues); + break; + case "Partial": { + DebugValueMap globalMap = new DebugValueMap("Global"); + for (DebugValueMap map : topLevelMaps) { + flattenChildren(map, globalMap); + } + globalMap.normalize(); + printMap(new DebugValueScope(null, globalMap), sortedValues); + break; + } + case "Complete": { + DebugValueMap globalMap = new DebugValueMap("Global"); + for (DebugValueMap map : topLevelMaps) { + globalMap.addChild(map); + } + globalMap.group(); + globalMap.normalize(); + printMap(new DebugValueScope(null, globalMap), sortedValues); + break; + } + case "Thread": + for (DebugValueMap map : topLevelMaps) { + TTY.println("Showing the results for thread: " + map.getName()); + map.group(); + map.normalize(); + printMap(new DebugValueScope(null, map), sortedValues); + } + break; + default: + throw new GraalInternalError("Unknown summary type: %s", summary); + } + if (reset) { + for (DebugValueMap topLevelMap : topLevelMaps) { + topLevelMap.reset(); + } + } + } catch (Throwable e) { + // Don't want this to change the exit status of the VM + PrintStream err = System.err; + err.println("Error while printing debug values:"); + e.printStackTrace(); + } + } + if (phase != null) { + TTY.println(""); + } else { + TTY.println(""); + } + } + } + private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) { globalMap.addChild(map); for (DebugValueMap child : map.getChildren()) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Sat Nov 09 21:34:07 2013 +0100 @@ -83,12 +83,16 @@ private static final int ACTION_MASK = 0x07; private static final int REASON_SHIFT = 3; private static final int REASON_MASK = 0x1f; + private static final int DEBUG_SHIFT = 8; + private static final int DEBUG_MASK = 0x7fffff; @Override - public Constant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) { + public Constant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int speculationId) { int actionValue = convertDeoptAction(action); int reasonValue = convertDeoptReason(reason); - Constant c = Constant.forInt(~(((reasonValue) << REASON_SHIFT) + ((actionValue) << ACTION_SHIFT))); + int speculationValue = speculationId & DEBUG_MASK; + Constant c = Constant.forInt(~((speculationValue << DEBUG_SHIFT) | (reasonValue << REASON_SHIFT) | (actionValue << ACTION_SHIFT))); + assert c.asInt() < 0; return c; } @@ -104,6 +108,10 @@ return action; } + public short decodeSpeculationId(Constant constant) { + return (short) (((~constant.asInt()) >> DEBUG_SHIFT) & DEBUG_MASK); + } + public int convertDeoptAction(DeoptimizationAction action) { switch (action) { case None: diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Sat Nov 09 21:34:07 2013 +0100 @@ -23,7 +23,9 @@ package com.oracle.graal.hotspot.replacements; import static com.oracle.graal.api.code.UnsignedMath.*; +import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.Options.*; import static com.oracle.graal.nodes.PiArrayNode.*; import static com.oracle.graal.nodes.PiNode.*; import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*; @@ -64,11 +66,11 @@ public static final LocationIdentity INIT_LOCATION = new NamedLocationIdentity("Initialization"); - public static class Options { + static class Options { //@formatter:off @Option(help = "") - private static final OptionValue ProfileAllocations = new OptionValue<>(false); + static final OptionValue ProfileAllocations = new OptionValue<>(false); //@formatter:on } @@ -114,7 +116,7 @@ @Fold private static boolean doProfile() { - return Options.ProfileAllocations.getValue(); + return ProfileAllocations.getValue(); } private static void profileAllocation(String path, long size, String typeContext) { @@ -315,7 +317,7 @@ args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); args.addConst("fillContents", newInstanceNode.fillContents()); - args.addConst("typeContext", MetaUtil.toJavaName(type, false)); + args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(type, false) : ""); SnippetTemplate template = template(args); Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args); @@ -342,7 +344,7 @@ args.addConst("headerSize", headerSize); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", newArrayNode.fillContents()); - args.addConst("typeContext", MetaUtil.toJavaName(arrayType, false)); + args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(arrayType, false) : ""); SnippetTemplate template = template(args); Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -49,6 +49,7 @@ import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; /** @@ -56,6 +57,13 @@ */ public class GraphBuilderPhase extends Phase { + static class Options { + // @formatter:off + @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode") + public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); + // @formatter:on + } + public static final class RuntimeCalls { public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", Object.class); @@ -63,14 +71,14 @@ } /** - * The minimum value to which {@link GraalOptions#TraceBytecodeParserLevel} must be set to trace - * the bytecode instructions as they are parsed. + * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the + * bytecode instructions as they are parsed. */ public static final int TRACELEVEL_INSTRUCTIONS = 1; /** - * The minimum value to which {@link GraalOptions#TraceBytecodeParserLevel} must be set to trace - * the frame state before each bytecode instruction as it is parsed. + * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the + * frame state before each bytecode instruction as it is parsed. */ public static final int TRACELEVEL_STATE = 2; @@ -739,7 +747,7 @@ ValueNode b = mirror ? x : y; CompareNode condition; - assert a.kind() != Kind.Double && a.kind() != Kind.Float; + assert !a.kind().isNumericFloat(); if (cond == Condition.EQ || cond == Condition.NE) { if (a.kind() == Kind.Object) { condition = new ObjectEqualsNode(a, b); @@ -1787,8 +1795,10 @@ } } + private final int traceLevel = Options.TraceBytecodeParserLevel.getValue(); + private void traceState() { - if (TraceBytecodeParserLevel.getValue() >= TRACELEVEL_STATE && Debug.isLogEnabled()) { + if (traceLevel >= TRACELEVEL_STATE && Debug.isLogEnabled()) { Debug.log(String.format("| state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method)); for (int i = 0; i < frameState.localsSize(); ++i) { ValueNode value = frameState.localAt(i); @@ -2018,7 +2028,7 @@ } private void traceInstruction(int bci, int opcode, boolean blockStart) { - if (TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { + if (traceLevel >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { StringBuilder sb = new StringBuilder(40); sb.append(blockStart ? '+' : '|'); if (bci < 10) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Sat Nov 09 21:34:07 2013 +0100 @@ -188,57 +188,57 @@ public static class LoadCompressedPointer extends LoadOp { - private long narrowOopBase; - private int narrowOopShift; - private int logMinObjAlignment; + private final long base; + private final int shift; + private final int alignment; @Temp({REG}) private AllocatableValue scratch; - public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, HSAILAddressValue address, LIRFrameState state, long narrowOopBase, int narrowOopShift, - int logMinObjAlignment) { + public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, HSAILAddressValue address, LIRFrameState state, long base, int shift, int alignment) { super(kind, result, address, state); - this.narrowOopBase = narrowOopBase; - this.narrowOopShift = narrowOopShift; - this.logMinObjAlignment = logMinObjAlignment; + this.base = base; + this.shift = shift; + this.alignment = alignment; this.scratch = scratch; - assert kind == Kind.Object; + assert kind == Kind.Object || kind == Kind.Long; } @Override public void emitMemAccess(HSAILAssembler masm) { // we will do a 32 bit load, zero extending into a 64 bit register masm.emitLoad(result, address.toAddress(), "u32"); - decodePointer(masm, result, narrowOopBase, narrowOopShift, logMinObjAlignment); + boolean testForNull = (kind == Kind.Object); + decodePointer(masm, result, base, shift, alignment, testForNull); } } public static class StoreCompressedPointer extends HSAILLIRInstruction { protected final Kind kind; - private long narrowOopBase; - private int narrowOopShift; - private int logMinObjAlignment; + private final long base; + private final int shift; + private final int alignment; @Temp({REG}) private AllocatableValue scratch; @Alive({REG}) protected AllocatableValue input; @Alive({COMPOSITE}) protected HSAILAddressValue address; @State protected LIRFrameState state; - public StoreCompressedPointer(Kind kind, HSAILAddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long narrowOopBase, int narrowOopShift, - int logMinObjAlignment) { - this.narrowOopBase = narrowOopBase; - this.narrowOopShift = narrowOopShift; - this.logMinObjAlignment = logMinObjAlignment; + public StoreCompressedPointer(Kind kind, HSAILAddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long base, int shift, int alignment) { + this.base = base; + this.shift = shift; + this.alignment = alignment; this.scratch = scratch; this.kind = kind; this.address = address; this.state = state; this.input = input; - assert kind == Kind.Object; + assert kind == Kind.Object || kind == Kind.Long; } @Override public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) { masm.emitMov(scratch, input); - encodePointer(masm, scratch, narrowOopBase, narrowOopShift, logMinObjAlignment); + boolean testForNull = (kind == Kind.Object); + encodePointer(masm, scratch, base, shift, alignment, testForNull); if (state != null) { throw new InternalError("NYI"); // tasm.recordImplicitException(masm.codeBuffer.position(), state); @@ -247,24 +247,24 @@ } } - private static void encodePointer(HSAILAssembler masm, Value scratch, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { - if (narrowOopBase == 0 && narrowOopShift == 0) { + private static void encodePointer(HSAILAssembler masm, Value scratch, long base, int shift, int alignment, boolean testForNull) { + if (base == 0 && shift == 0) { return; } - if (narrowOopShift != 0) { - assert logMinObjAlignment == narrowOopShift : "Encode algorithm is wrong"; + if (shift != 0) { + assert alignment == shift : "Encode algorithm is wrong"; } - masm.emitCompressedOopEncode(scratch, narrowOopBase, narrowOopShift); + masm.emitCompressedOopEncode(scratch, base, shift, testForNull); } - private static void decodePointer(HSAILAssembler masm, Value result, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { - if (narrowOopBase == 0 && narrowOopShift == 0) { + private static void decodePointer(HSAILAssembler masm, Value result, long base, int shift, int alignment, boolean testForNull) { + if (base == 0 && shift == 0) { return; } - if (narrowOopShift != 0) { - assert logMinObjAlignment == narrowOopShift : "Decode algorithm is wrong"; + if (shift != 0) { + assert alignment == shift : "Decode algorithm is wrong"; } - masm.emitCompressedOopDecode(result, narrowOopBase, narrowOopShift); + masm.emitCompressedOopDecode(result, base, shift, testForNull); } public static class LeaOp extends HSAILLIRInstruction { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Sat Nov 09 21:34:07 2013 +0100 @@ -24,7 +24,7 @@ import java.util.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.MoveOp; import com.oracle.graal.nodes.cfg.*; /** @@ -182,9 +182,16 @@ assert numSux == 2 : "method should not be called otherwise"; - assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump"; + LIRInstruction lastInstruction = instructions.get(instructions.size() - 1); + if (lastInstruction instanceof StandardOp.FallThroughOp) { + assert ((StandardOp.FallThroughOp) lastInstruction).fallThroughTarget() != null : "block must end with unconditional jump"; + // fall through ops like switches cannot be optimized anyway - they have input operands + return; + } else { + assert lastInstruction instanceof StandardOp.JumpOp : "block must end with unconditional jump"; + } - if (instructions.get(instructions.size() - 1).hasState()) { + if (lastInstruction.hasState()) { // cannot optimize instructions when debug info is needed return; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Sat Nov 09 21:34:07 2013 +0100 @@ -186,7 +186,7 @@ * including long constants that fit into the 32-bit range. */ public int asIntConst(Value value) { - assert (value.getKind().getStackKind() == Kind.Int || value.getKind() == Kind.Long) && isConstant(value); + assert (value.getKind().isNumericInteger()) && isConstant(value); Constant constant = (Constant) value; assert !codeCache.needsDataPatch(constant) : constant + " should be in a DataPatch"; long c = constant.asLong(); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java Sat Nov 09 21:34:07 2013 +0100 @@ -123,19 +123,25 @@ Kind fromKind = phi.kind(); StructuredGraph graph = graph(); ValueNode stride = strideNode(); - ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount); ValueNode initNode = this.initNode(); if (fromKind != kind) { stride = graph.unique(new ConvertNode(fromKind, kind, stride)); - maxTripCount = graph.unique(new ConvertNode(fromKind, kind, maxTripCount)); initNode = graph.unique(new ConvertNode(fromKind, kind, initNode)); } + ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount); + if (maxTripCount.kind() != kind) { + maxTripCount = graph.unique(new ConvertNode(maxTripCount.kind(), kind, maxTripCount)); + } return IntegerArithmeticNode.add(graph, IntegerArithmeticNode.mul(graph, stride, IntegerArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode); } @Override public ValueNode exitValueNode() { + Kind kind = phi.kind(); ValueNode maxTripCount = loop.counted().maxTripCountNode(false); + if (maxTripCount.kind() != kind) { + maxTripCount = graph().unique(new ConvertNode(maxTripCount.kind(), kind, maxTripCount)); + } return IntegerArithmeticNode.add(graph(), IntegerArithmeticNode.mul(graph(), strideNode(), maxTripCount), initNode()); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Sat Nov 09 21:34:07 2013 +0100 @@ -26,6 +26,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.NodeClass.NodeClassIterator; import com.oracle.graal.graph.NodeClass.Position; import com.oracle.graal.nodes.*; @@ -59,7 +60,7 @@ LoopBeginNode loopBegin = loop.loopBegin(); StructuredGraph graph = loopBegin.graph(); while (!loopBegin.isDeleted()) { - int mark = graph.getMark(); + Mark mark = graph.getMark(); peel(loop); canonicalizer.applyIncremental(graph, context, mark); if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -31,12 +31,18 @@ private final DeoptimizationAction action; private final DeoptimizationReason reason; + private final int speculationId; public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason) { + this(action, reason, (short) 0); + } + + public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason, int speculationId) { assert action != null; assert reason != null; this.action = action; this.reason = reason; + this.speculationId = speculationId; } public DeoptimizationAction action() { @@ -49,12 +55,12 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.emitDeoptimize(gen.getMetaAccess().encodeDeoptActionAndReason(action, reason), this); + gen.emitDeoptimize(gen.getMetaAccess().encodeDeoptActionAndReason(action, reason, speculationId), this); } @Override public ValueNode getActionAndReason(MetaAccessProvider metaAccess) { - return ConstantNode.forConstant(metaAccess.encodeDeoptActionAndReason(action, reason), metaAccess, graph()); + return ConstantNode.forConstant(metaAccess.encodeDeoptActionAndReason(action, reason, speculationId), metaAccess, graph()); } @NodeIntrinsic diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -51,7 +51,7 @@ @Input(notDataflow = true) private MergeNode merge; @Input private final NodeInputList values = new NodeInputList<>(this); private final PhiType type; - private final Object identity; + private final LocationIdentity identity; /** * Create a value phi ({@link PhiType#Value}) with the specified kind. @@ -77,7 +77,7 @@ * @param type the type of the new phi * @param merge the merge that the new phi belongs to */ - public PhiNode(PhiType type, MergeNode merge, Object identity) { + public PhiNode(PhiType type, MergeNode merge, LocationIdentity identity) { super(type.stamp); assert type.stamp != null : merge + " " + type; this.type = type; @@ -93,7 +93,7 @@ return merge; } - public Object getIdentity() { + public LocationIdentity getIdentity() { assert type != PhiType.Value; return identity; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ValueNumberable; import com.oracle.graal.graph.spi.*; @@ -41,9 +42,9 @@ @Input(notDataflow = true) private AbstractBeginNode proxyPoint; @Input private ValueNode value; private final PhiType type; - private final Object identity; + private final LocationIdentity identity; - public ProxyNode(ValueNode value, AbstractBeginNode exit, PhiType type, Object identity) { + public ProxyNode(ValueNode value, AbstractBeginNode exit, PhiType type, LocationIdentity identity) { super(type == PhiType.Value ? value.stamp() : type.stamp); this.type = type; this.identity = identity; @@ -69,7 +70,7 @@ return type; } - public Object getIdentity() { + public LocationIdentity getIdentity() { assert type != PhiType.Value; return identity; } @@ -113,7 +114,7 @@ return graph.unique(new ProxyNode(value, exit, PhiType.Value, null)); } - public static ProxyNode forMemory(ValueNode value, AbstractBeginNode exit, Object location, StructuredGraph graph) { + public static ProxyNode forMemory(ValueNode value, AbstractBeginNode exit, LocationIdentity location, StructuredGraph graph) { return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location)); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -140,29 +140,54 @@ setX(convertX.value()); setY(convertY.value()); } + } else if (x() instanceof ConvertNode && y().isConstant()) { + ConvertNode convertX = (ConvertNode) x(); + ConstantNode newY = canonicalConvertConstant(convertX, y().asConstant()); + if (newY != null) { + setX(convertX.value()); + setY(newY); + } + } else if (y() instanceof ConvertNode && x().isConstant()) { + ConvertNode convertY = (ConvertNode) y(); + ConstantNode newX = canonicalConvertConstant(convertY, x().asConstant()); + if (newX != null) { + setX(newX); + setY(convertY.value()); + } } return this; } + private static ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) { + if (convert.isLossless()) { + assert constant.getKind() == convert.getToKind(); + Constant reverseConverted = ConvertNode.convert(convert.getToKind(), convert.getFromKind(), constant); + if (convert.evalConst(reverseConverted).equals(constant)) { + return ConstantNode.forPrimitive(reverseConverted, convert.graph()); + } + } + return null; + } + public static CompareNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) { assert x.kind() == y.kind(); assert condition.isCanonical() : "condition is not canonical: " + condition; - assert x.kind() != Kind.Double && x.kind() != Kind.Float; + assert !x.kind().isNumericFloat(); CompareNode comparison; if (condition == Condition.EQ) { if (x.kind() == Kind.Object) { comparison = new ObjectEqualsNode(x, y); } else { - assert x.kind().getStackKind() == Kind.Int || x.kind() == Kind.Long; + assert x.kind().isNumericInteger(); comparison = new IntegerEqualsNode(x, y); } } else if (condition == Condition.LT) { - assert x.kind().getStackKind() == Kind.Int || x.kind() == Kind.Long; + assert x.kind().isNumericInteger(); comparison = new IntegerLessThanNode(x, y); } else { assert condition == Condition.BT; - assert x.kind().getStackKind() == Kind.Int || x.kind() == Kind.Long; + assert x.kind().isNumericInteger(); comparison = new IntegerBelowThanNode(x, y); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java Sat Nov 09 21:34:07 2013 +0100 @@ -322,7 +322,7 @@ * the comparison is known to be false */ public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection) { - assert lt.getKind() != Kind.Double && lt.getKind() != Kind.Float && rt.getKind() != Kind.Double && rt.getKind() != Kind.Float; + assert !lt.getKind().isNumericFloat() && !rt.getKind().isNumericFloat(); return foldCondition(lt, rt, constantReflection, false); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -87,9 +87,7 @@ throw GraalInternalError.shouldNotReachHere(); } - public Constant evalConst(Constant... inputs) { - assert inputs.length == 1; - Constant c = inputs[0]; + public static Constant convert(Kind from, Kind to, Constant c) { switch (from) { case Byte: byte byteVal = (byte) c.asInt(); @@ -228,10 +226,20 @@ throw GraalInternalError.shouldNotReachHere(); } + public Constant evalConst(Constant... inputs) { + assert inputs.length == 1; + return convert(from, to, inputs[0]); + } + @Override public Node canonical(CanonicalizerTool tool) { if (value.isConstant()) { return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph()); + } else if (value instanceof ConvertNode) { + ConvertNode other = (ConvertNode) value; + if (other.isLossless() && other.to != Kind.Char) { + return graph().unique(new ConvertNode(other.from, this.to, other.value())); + } } return this; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -32,6 +32,7 @@ public FloatArithmeticNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { super(kind, x, y); + assert kind.isNumericFloat(); this.isStrictFP = isStrictFP; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -97,7 +97,7 @@ public static boolean isIntegerAddition(ValueNode result, ValueNode a, ValueNode b) { Kind kind = result.kind(); - if (kind != a.kind() || kind != b.kind() || !(kind.getStackKind() == Kind.Int || kind == Kind.Long)) { + if (kind != a.kind() || kind != b.kind() || !kind.isNumericInteger()) { return false; } if (result.isConstant() && a.isConstant() && b.isConstant()) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -30,7 +30,7 @@ public IntegerArithmeticNode(Kind kind, ValueNode x, ValueNode y) { super(kind, x, y); - assert kind == Kind.Int || kind == Kind.Long; + assert kind.isNumericInteger(); } public static IntegerAddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -39,8 +39,8 @@ */ public IntegerBelowThanNode(ValueNode x, ValueNode y) { super(x, y); - assert x.kind() != Kind.Double && x.kind() != Kind.Float && x.kind() != Kind.Object; - assert y.kind() != Kind.Double && y.kind() != Kind.Float && y.kind() != Kind.Object; + assert !x.kind().isNumericFloat() && x.kind() != Kind.Object; + assert !y.kind().isNumericFloat() && y.kind() != Kind.Object; } @Override diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -38,8 +38,8 @@ */ public IntegerEqualsNode(ValueNode x, ValueNode y) { super(x, y); - assert x.kind() != Kind.Double && x.kind() != Kind.Float && x.kind() != Kind.Object; - assert y.kind() != Kind.Double && y.kind() != Kind.Float && y.kind() != Kind.Object; + assert !x.kind().isNumericFloat() && x.kind() != Kind.Object; + assert !y.kind().isNumericFloat() && y.kind() != Kind.Object; } @Override diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -39,8 +39,8 @@ */ public IntegerLessThanNode(ValueNode x, ValueNode y) { super(x, y); - assert x.kind() != Kind.Double && x.kind() != Kind.Float && x.kind() != Kind.Object; - assert y.kind() != Kind.Double && y.kind() != Kind.Float && y.kind() != Kind.Object; + assert !x.kind().isNumericFloat() && x.kind() != Kind.Object; + assert !y.kind().isNumericFloat() && y.kind() != Kind.Object; } @Override diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -22,10 +22,11 @@ */ package com.oracle.graal.nodes.extended; +import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; -public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access { +public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess { @Input private ValueNode object; @Input private LocationNode location; @@ -46,6 +47,10 @@ return location; } + public LocationIdentity getLocationIdentity() { + return location.getLocationIdentity(); + } + public boolean getNullCheck() { return nullCheck; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -51,7 +51,7 @@ this.lastLocationAccess = lastLocationAccess; } - public Node lastLocationAccess() { + public Node getLastLocationAccess() { return lastLocationAccess; } @@ -90,7 +90,7 @@ @Override public boolean verify() { - Node lla = lastLocationAccess(); + Node lla = getLastLocationAccess(); assert lla == null || isMemoryCheckPoint(lla) || isMemoryPhi(lla) || isMemoryProxy(lla) : "lastLocationAccess of " + this + " should be a MemoryCheckpoint, but is " + lla; return super.verify(); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,39 @@ +/* + * 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.nodes.extended; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; + +/** + * This interface marks nodes that access some memory location, and that have an edge to the last + * node that kills this location. + */ +public interface MemoryAccess { + + LocationIdentity getLocationIdentity(); + + Node getLastLocationAccess(); + + void setLastLocationAccess(Node lla); +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -77,7 +77,7 @@ return ConstantNode.forConstant(constant, metaAccess, read.graph()); } } - } else if (object.kind() == Kind.Long || object.kind().getStackKind() == Kind.Int) { + } else if (object.kind().isNumericInteger()) { long base = object.asConstant().asLong(); if (base != 0L) { Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, null, base + displacement, compressible); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -73,6 +73,7 @@ // the null check and if a field is found, the offset is so small that this is // never a valid access of an arbitrary address. if (field != null && field.getKind() == this.accessKind()) { + assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase"; return cloneAsFieldAccess(field); } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.extended; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.LocationNode.Location; import com.oracle.graal.nodes.spi.*; @@ -32,12 +33,14 @@ /** * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}. */ -public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, Virtualizable { +public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Virtualizable { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; private final boolean initialization; + @Input private Node lastLocationAccess; + public FrameState stateAfter() { return stateAfter; } @@ -89,6 +92,15 @@ return location().getLocationIdentity(); } + public Node getLastLocationAccess() { + return lastLocationAccess; + } + + public void setLastLocationAccess(Node lla) { + updateUsages(lastLocationAccess, lla); + lastLocationAccess = lla; + } + @Override public void virtualize(VirtualizerTool tool) { if (location() instanceof ConstantLocationNode) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Sat Nov 09 21:34:07 2013 +0100 @@ -57,4 +57,6 @@ * Gets the closest fixed node preceding the node currently being lowered. */ FixedWithNextNode lastFixedNode(); + + GuardingNode getCurrentGuardAnchor(); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.options.test/src/com/oracle/graal/options/test/TestOptionValue.java --- a/graal/com.oracle.graal.options.test/src/com/oracle/graal/options/test/TestOptionValue.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.options.test/src/com/oracle/graal/options/test/TestOptionValue.java Sat Nov 09 21:34:07 2013 +0100 @@ -25,6 +25,8 @@ import static com.oracle.graal.options.test.TestOptionValue.Options.*; import static org.junit.Assert.*; +import java.util.*; + import org.junit.*; import com.oracle.graal.options.*; @@ -99,4 +101,27 @@ // expected } } + + @Test + public void toStringTest() { + assertEquals("com.oracle.graal.options.test.TestOptionValue$Options.Mutable=original", Mutable.toString()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals("com.oracle.graal.options.test.TestOptionValue$Options.Mutable=override1", Mutable.toString()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals("com.oracle.graal.options.test.TestOptionValue$Options.Mutable=override2", Mutable.toString()); + } + } + } + + @Test + public void getValuesTest() { + assertEquals(Arrays.asList("original"), Mutable.getValues(null)); + assertEquals(Arrays.asList(true), Stable.getValues(null)); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals(Arrays.asList("override1", "original"), Mutable.getValues(null)); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals(Arrays.asList("override2", "override1", "original"), Mutable.getValues(null)); + } + } + } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Sat Nov 09 21:34:07 2013 +0100 @@ -22,6 +22,7 @@ */ package com.oracle.graal.options; +import java.io.*; import java.util.*; import java.util.Map.Entry; @@ -136,8 +137,24 @@ private OptionDescriptor descriptor; + private long reads; + private OptionValue next; + private static OptionValue head; + + private static final boolean ShowReadsHistogram = Boolean.getBoolean("graal.showOptionValueReadsHistogram"); + + private static void addToHistogram(OptionValue option) { + if (ShowReadsHistogram) { + synchronized (OptionValue.class) { + option.next = head; + head = option; + } + } + } + public OptionValue(T value) { this.value = value; + addToHistogram(this); } private static final Object UNINITIALIZED = "UNINITIALIZED"; @@ -149,6 +166,7 @@ @SuppressWarnings("unchecked") protected OptionValue() { this.value = (T) UNINITIALIZED; + addToHistogram(this); } /** @@ -167,21 +185,25 @@ /** * Gets the name of this option. The name for an option value with a null - * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is {@code ""}. + * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of + * {@link Object#toString()}. */ public String getName() { - return descriptor == null ? "" : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName()); + return descriptor == null ? super.toString() : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName()); } @Override public String toString() { - return getName() + "=" + value; + return getName() + "=" + getValue(); } /** * Gets the value of this option. */ public T getValue() { + if (ShowReadsHistogram) { + reads++; + } if (!(this instanceof StableOptionValue)) { OverrideScope overrideScope = overrideScopes.get(); if (overrideScope != null) { @@ -198,6 +220,26 @@ } /** + * Gets the values of this option including overridden values. + * + * @param c the collection to which the values are added. If null, one is allocated. + * @return the collection to which the values were added in order from most overridden to + * current value + */ + @SuppressWarnings("unchecked") + public Collection getValues(Collection c) { + Collection values = c == null ? new ArrayList() : c; + if (!(this instanceof StableOptionValue)) { + OverrideScope overrideScope = overrideScopes.get(); + if (overrideScope != null) { + overrideScope.getOverrides(this, (Collection) values); + } + } + values.add(value); + return values; + } + + /** * Sets the value of this option. */ @SuppressWarnings("unchecked") @@ -214,6 +256,8 @@ abstract T getOverride(OptionValue option); + abstract void getOverrides(OptionValue option, Collection c); + public abstract void close(); } @@ -246,6 +290,13 @@ } @Override + void getOverrides(OptionValue key, Collection c) { + if (key == this.option) { + c.add(value); + } + } + + @Override public void close() { overrideScopes.set(null); } @@ -311,10 +362,52 @@ } @Override + void getOverrides(OptionValue option, Collection c) { + Object v = overrides.get(option); + if (v != null) { + c.add(v); + } + if (parent != null) { + parent.getOverrides(option, c); + } + } + + @Override public void close() { if (!overrides.isEmpty()) { overrideScopes.set(parent); } } } + + static { + if (ShowReadsHistogram) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + ArrayList> options = new ArrayList<>(); + for (OptionValue option = head; option != null; option = option.next) { + options.add(option); + } + Collections.sort(options, new Comparator>() { + + public int compare(OptionValue o1, OptionValue o2) { + if (o1.reads < o2.reads) { + return -1; + } else if (o1.reads > o2.reads) { + return 1; + } else { + return o1.getName().compareTo(o2.getName()); + } + } + }); + PrintStream out = System.out; + out.println("=== OptionValue reads histogram ==="); + for (OptionValue option : options) { + out.println(option.reads + "\t" + option); + } + } + }); + } + } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -28,6 +28,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; @@ -71,14 +72,14 @@ } /** - * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by this + * @param newNodesMark only the {@linkplain Graph#getNewNodes(Mark) new nodes} specified by this * mark are processed */ - public void applyIncremental(StructuredGraph graph, PhaseContext context, int newNodesMark) { + public void applyIncremental(StructuredGraph graph, PhaseContext context, Mark newNodesMark) { applyIncremental(graph, context, newNodesMark, true); } - public void applyIncremental(StructuredGraph graph, PhaseContext context, int newNodesMark, boolean dumpGraph) { + public void applyIncremental(StructuredGraph graph, PhaseContext context, Mark newNodesMark, boolean dumpGraph) { new Instance(context, canonicalizeReads, newNodesMark, customCanonicalizer).apply(graph, dumpGraph); } @@ -94,11 +95,11 @@ new Instance(context, canonicalizeReads, workingSet, customCanonicalizer).apply(graph, dumpGraph); } - public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable workingSet, int newNodesMark) { + public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable workingSet, Mark newNodesMark) { applyIncremental(graph, context, workingSet, newNodesMark, true); } - public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable workingSet, int newNodesMark, boolean dumpGraph) { + public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable workingSet, Mark newNodesMark, boolean dumpGraph) { new Instance(context, canonicalizeReads, workingSet, newNodesMark, customCanonicalizer).apply(graph, dumpGraph); } @@ -109,7 +110,7 @@ private static final class Instance extends Phase { - private final int newNodesMark; + private final Mark newNodesMark; private final PhaseContext context; private final CustomCanonicalizer customCanonicalizer; private final Iterable initWorkingSet; @@ -119,18 +120,18 @@ private Tool tool; private Instance(PhaseContext context, boolean canonicalizeReads, CustomCanonicalizer customCanonicalizer) { - this(context, canonicalizeReads, null, 0, customCanonicalizer); + this(context, canonicalizeReads, null, null, customCanonicalizer); } private Instance(PhaseContext context, boolean canonicalizeReads, Iterable workingSet, CustomCanonicalizer customCanonicalizer) { - this(context, canonicalizeReads, workingSet, 0, customCanonicalizer); + this(context, canonicalizeReads, workingSet, null, customCanonicalizer); } - private Instance(PhaseContext context, boolean canonicalizeReads, int newNodesMark, CustomCanonicalizer customCanonicalizer) { + private Instance(PhaseContext context, boolean canonicalizeReads, Mark newNodesMark, CustomCanonicalizer customCanonicalizer) { this(context, canonicalizeReads, null, newNodesMark, customCanonicalizer); } - private Instance(PhaseContext context, boolean canonicalizeReads, Iterable workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) { + private Instance(PhaseContext context, boolean canonicalizeReads, Iterable workingSet, Mark newNodesMark, CustomCanonicalizer customCanonicalizer) { super("Canonicalizer"); this.newNodesMark = newNodesMark; this.context = context; @@ -141,13 +142,14 @@ @Override protected void run(StructuredGraph graph) { + boolean wholeGraph = newNodesMark == null || newNodesMark.isStart(); if (initWorkingSet == null) { - workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE); + workList = graph.createNodeWorkList(wholeGraph, MAX_ITERATION_PER_NODE); } else { workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE); workList.addAll(initWorkingSet); } - if (newNodesMark > 0) { + if (!wholeGraph) { workList.addAll(graph.getNewNodes(newNodesMark)); } tool = new Tool(); @@ -182,7 +184,7 @@ return; } StructuredGraph graph = (StructuredGraph) node.graph(); - int mark = graph.getMark(); + Mark mark = graph.getMark(); if (!tryKillUnused(node)) { if (!tryCanonicalize(node, nodeClass)) { if (node instanceof ValueNode) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -176,6 +176,10 @@ @Override protected MemoryMapImpl processNode(FixedNode node, MemoryMapImpl state) { + if (node instanceof MemoryAccess) { + processAccess((MemoryAccess) node, state); + } + if (node instanceof FloatableAccessNode && execmode == ExecutionMode.CREATE_FLOATING_READS) { processFloatable((FloatableAccessNode) node, state); } else if (node instanceof MemoryCheckpoint.Single) { @@ -191,6 +195,14 @@ return state; } + private static void processAccess(MemoryAccess access, MemoryMapImpl state) { + LocationIdentity locationIdentity = access.getLocationIdentity(); + if (locationIdentity != LocationIdentity.ANY_LOCATION) { + ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity); + access.setLastLocationAccess(lastLocationAccess); + } + } + private static void processCheckpoint(MemoryCheckpoint.Single checkpoint, MemoryMapImpl state) { processIdentity(checkpoint.getLocationIdentity(), checkpoint, state); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; @@ -53,6 +54,12 @@ * does the actual control-flow expansion of the remaining {@link GuardNode GuardNodes}. */ public class GuardLoweringPhase extends BasePhase { + static class Options { + //@formatter:off + @Option(help = "") + public static final OptionValue UseGuardIdAsSpeculationId = new OptionValue<>(false); + //@formatter:on + } private static class UseImplicitNullChecks extends ScheduledNodeIterator { @@ -124,9 +131,11 @@ private static class LowerGuards extends ScheduledNodeIterator { private final Block block; + private boolean useGuardIdAsSpeculationId; public LowerGuards(Block block) { this.block = block; + this.useGuardIdAsSpeculationId = Options.UseGuardIdAsSpeculationId.getValue(); } @Override @@ -144,7 +153,8 @@ private void lowerToIf(GuardNode guard) { StructuredGraph graph = guard.graph(); AbstractBeginNode fastPath = graph.add(new BeginNode()); - DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason())); + @SuppressWarnings("deprecation") + DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason(), useGuardIdAsSpeculationId ? guard.getId() : 0)); AbstractBeginNode deoptBranch = AbstractBeginNode.begin(deopt); AbstractBeginNode trueSuccessor; AbstractBeginNode falseSuccessor; diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IncrementalCanonicalizerPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -44,7 +45,7 @@ @Override protected void run(StructuredGraph graph, C context) { - int newNodesMark = graph.getMark(); + Mark newNodesMark = graph.getMark(); final Set changedNodes = new HashSet<>(); NodeChangedListener listener = new NodeChangedListener() { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -32,6 +32,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @@ -180,7 +181,7 @@ private void doInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, Assumptions callerAssumptions, HighTierContext context) { StructuredGraph callerGraph = callerGraphInfo.graph(); - int markBeforeInlining = callerGraph.getMark(); + Mark markBeforeInlining = callerGraph.getMark(); InlineInfo callee = calleeInfo.callee(); try { List invokeUsages = callee.invoke().asNode().usages().snapshot(); @@ -190,7 +191,7 @@ Debug.dump(callerGraph, "after %s", callee); if (OptCanonicalizer.getValue()) { - int markBeforeCanonicalization = callerGraph.getMark(); + Mark markBeforeCanonicalization = callerGraph.getMark(); canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining); // process invokes that are possibly created during canonicalization diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -29,6 +29,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.GuardsStage; @@ -49,8 +50,8 @@ final class LoweringToolImpl implements LoweringTool { private final PhaseContext context; - private final GuardingNode guardAnchor; private final NodeBitMap activeGuards; + private GuardingNode guardAnchor; private FixedWithNextNode lastFixedNode; private ControlFlowGraph cfg; @@ -93,6 +94,11 @@ } @Override + public GuardingNode getCurrentGuardAnchor() { + return guardAnchor; + } + + @Override public GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object) { if (ObjectStamp.isObjectNonNull(object)) { // Short cut creation of null check guard if the object is known to be non-null. @@ -169,10 +175,10 @@ * @throws AssertionError if the check fails */ private boolean checkPostLowering(StructuredGraph graph, PhaseContext context) { - int expectedMark = graph.getMark(); + Mark expectedMark = graph.getMark(); lower(graph, context, 1); - int mark = graph.getMark(); - assert mark == expectedMark : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(mark).snapshot(); + Mark mark = graph.getMark(); + assert mark.equals(expectedMark) : graph + ": a second round in the current lowering phase introduced these new nodes: " + graph.getNewNodes(mark).snapshot(); return true; } @@ -198,15 +204,15 @@ * @param preLoweringMark the graph mark before {@code node} was lowered * @throws AssertionError if the check fails */ - private static boolean checkPostNodeLowering(Node node, LoweringToolImpl loweringTool, int preLoweringMark) { + private static boolean checkPostNodeLowering(Node node, LoweringToolImpl loweringTool, Mark preLoweringMark) { StructuredGraph graph = (StructuredGraph) node.graph(); - int postLoweringMark = graph.getMark(); + Mark postLoweringMark = graph.getMark(); NodeIterable newNodesAfterLowering = graph.getNewNodes(preLoweringMark); for (Node n : newNodesAfterLowering) { if (n instanceof Lowerable) { ((Lowerable) n).lower(loweringTool); - int mark = graph.getMark(); - assert postLoweringMark == mark : graph + ": lowering of " + node + " produced lowerable " + n + " that should have been recursively lowered as it introduces these new nodes: " + + Mark mark = graph.getMark(); + assert postLoweringMark.equals(mark) : graph + ": lowering of " + node + " produced lowerable " + n + " that should have been recursively lowered as it introduces these new nodes: " + graph.getNewNodes(postLoweringMark).snapshot(); } } @@ -236,7 +242,7 @@ if (anchor == null) { anchor = block.getBeginNode(); } - process(block, activeGuards, anchor); + anchor = process(block, activeGuards, anchor); // Process always reached block first. Block alwaysReachedBlock = block.getPostdominator(); @@ -261,9 +267,9 @@ } } - private void process(final Block b, final NodeBitMap activeGuards, final GuardingNode anchor) { + private GuardingNode process(final Block b, final NodeBitMap activeGuards, final GuardingNode startAnchor) { - final LoweringToolImpl loweringTool = new LoweringToolImpl(context, anchor, activeGuards, b.getBeginNode(), schedule.getCFG()); + final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode(), schedule.getCFG()); // Lower the instructions of this block. List nodes = schedule.nodesFor(b); @@ -285,8 +291,11 @@ if (node instanceof Lowerable) { assert checkUsagesAreScheduled(node); - int preLoweringMark = node.graph().getMark(); + Mark preLoweringMark = node.graph().getMark(); ((Lowerable) node).lower(loweringTool); + if (node == startAnchor && node.isDeleted()) { + loweringTool.guardAnchor = BeginNode.prevBegin(nextNode); + } assert checkPostNodeLowering(node, loweringTool, preLoweringMark); } @@ -310,6 +319,7 @@ loweringTool.setLastFixedNode((FixedWithNextNode) nextLastFixed); } } + return loweringTool.getCurrentGuardAnchor(); } /** diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -35,7 +35,7 @@ for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) { if (isReadEliminable(n)) { NodeMap nodeMap = n.graph().createNodeMap(); - ValueNode value = getValue(n, n.lastLocationAccess(), nodeMap); + ValueNode value = getValue(n, n.getLastLocationAccess(), nodeMap); Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value); graph.replaceFloating(n, value); } @@ -43,7 +43,7 @@ } private static boolean isReadEliminable(FloatingReadNode n) { - return isWrites(n, n.lastLocationAccess(), n.graph().createNodeBitMap()); + return isWrites(n, n.getLastLocationAccess(), n.graph().createNodeBitMap()); } private static boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -29,6 +29,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.Graph.DuplicationReplacement; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.extended.*; @@ -232,7 +233,7 @@ private void duplicate(PhaseContext phaseContext) { Debug.log("tail duplication at merge %s in %s", merge, graph.method()); - int startMark = graph.getMark(); + Mark startMark = graph.getMark(); ValueAnchorNode anchor = addValueAnchor(); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Sat Nov 09 21:34:07 2013 +0100 @@ -169,20 +169,12 @@ @Option(help = "") public static final OptionValue PrintProfilingInformation = new OptionValue<>(false); @Option(help = "") - public static final OptionValue PrintIRWithLIR = new OptionValue<>(false); - @Option(help = "") public static final OptionValue PrintCodeBytes = new OptionValue<>(false); @Option(help = "") public static final OptionValue PrintBailout = new OptionValue<>(false); @Option(help = "") - public static final OptionValue TraceLinearScanLevel = new OptionValue<>(0); - @Option(help = "") - public static final OptionValue TraceLIRGeneratorLevel = new OptionValue<>(0); - @Option(help = "") public static final OptionValue TraceEscapeAnalysis = new OptionValue<>(false); @Option(help = "") - public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); - @Option(help = "") public static final OptionValue ExitVMOnBailout = new OptionValue<>(false); @Option(help = "") public static final OptionValue ExitVMOnException = new OptionValue<>(true); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Sat Nov 09 21:34:07 2013 +0100 @@ -189,7 +189,7 @@ MergeNode mergeNode = (MergeNode) block.getBeginNode(); for (PhiNode phi : mergeNode.usages().filter(PhiNode.class)) { if (phi.type() == PhiType.Memory) { - LocationIdentity identity = (LocationIdentity) phi.getIdentity(); + LocationIdentity identity = phi.getIdentity(); locationKilledBy(identity, phi, currentState); } } @@ -266,7 +266,7 @@ for (Node usage : begin.usages()) { if (usage instanceof ProxyNode && ((ProxyNode) usage).type() == PhiType.Memory) { ProxyNode proxy = (ProxyNode) usage; - LocationIdentity identity = (LocationIdentity) proxy.getIdentity(); + LocationIdentity identity = proxy.getIdentity(); locationKilledBy(identity, proxy, exitState); } } @@ -347,7 +347,7 @@ if (n.location().getLocationIdentity() == FINAL_LOCATION) { continue; } - Node first = n.lastLocationAccess(); + Node first = n.getLastLocationAccess(); assert first != null; Map killMap = blockToKillMapInit.get(forKillLocation(first)); @@ -424,7 +424,7 @@ } else if (n instanceof FloatingReadNode) { FloatingReadNode frn = (FloatingReadNode) n; Debug.printf(" // from %s", frn.location().getLocationIdentity()); - Debug.printf(", lastAccess: %s", frn.lastLocationAccess()); + Debug.printf(", lastAccess: %s", frn.getLastLocationAccess()); Debug.printf(", object: %s", frn.object()); } else if (n instanceof GuardNode) { Debug.printf(", guard: %s", ((GuardNode) n).getGuard()); @@ -544,7 +544,7 @@ LocationIdentity locid = n.location().getLocationIdentity(); assert locid != FINAL_LOCATION; - Node upperBound = n.lastLocationAccess(); + Node upperBound = n.getLastLocationAccess(); Block upperBoundBlock = forKillLocation(upperBound); Block earliestBlock = earliestBlock(n); assert upperBoundBlock.dominates(earliestBlock) : "upper bound (" + upperBoundBlock + ") should dominate earliest (" + earliestBlock + ")"; @@ -925,7 +925,7 @@ FloatingReadNode frn = (FloatingReadNode) i; if (frn.location().getLocationIdentity() != FINAL_LOCATION) { reads.add(frn); - if (nodesFor(b).contains(frn.lastLocationAccess())) { + if (nodesFor(b).contains(frn.getLastLocationAccess())) { assert !beforeLastLocation.isMarked(frn); beforeLastLocation.mark(frn); } @@ -970,7 +970,7 @@ for (FloatingReadNode frn : new ArrayList<>(reads)) { // TODO: change to iterator? LocationIdentity readLocation = frn.location().getLocationIdentity(); assert readLocation != FINAL_LOCATION; - if (frn.lastLocationAccess() == node) { + 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 instanceof StartNode) && ANY_LOCATION == identity))) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Sat Nov 09 21:34:07 2013 +0100 @@ -408,7 +408,7 @@ } } Map props = new HashMap<>(); - int firstExternalNodeId = graph.getNodeCount() + graph.getDeletedNodeCount(); + int firstExternalNodeId = graph.getNodeCount() + graph.getTotalNodesDeleted(); for (Node node : graph.getNodes()) { for (Node input : node.inputs()) { if (input.isExternal()) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sat Nov 09 21:34:07 2013 +0100 @@ -36,6 +36,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.debug.*; +import com.oracle.graal.debug.internal.*; import com.oracle.graal.graph.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; @@ -79,14 +80,23 @@ this.snippetTemplateCache = new HashMap<>(); } + private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true")); + private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime"); + public StructuredGraph getSnippet(ResolvedJavaMethod method) { assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName(); assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : "Snippet must not be abstract or native"; - StructuredGraph graph = graphs.get(method); + StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null; if (graph == null) { - graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method), method.getAnnotation(Snippet.class).removeAllFrameStates())); - graph = graphs.get(method); + try (TimerCloseable a = SnippetPreparationTime.start()) { + StructuredGraph newGraph = makeGraph(method, null, inliningPolicy(method), method.getAnnotation(Snippet.class).removeAllFrameStates()); + if (UseSnippetGraphCache) { + return newGraph; + } + graphs.putIfAbsent(method, newGraph); + graph = graphs.get(method); + } } return graph; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Sat Nov 09 21:34:07 2013 +0100 @@ -23,7 +23,9 @@ package com.oracle.graal.replacements; import static com.oracle.graal.api.meta.LocationIdentity.*; +import static com.oracle.graal.api.meta.MetaUtil.*; +import java.io.*; import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; @@ -33,6 +35,7 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.loop.*; @@ -71,8 +74,20 @@ protected final ResolvedJavaMethod method; protected final boolean[] constantParameters; protected final boolean[] varargsParameters; + + /** + * Times instantiations of all templates derived form this snippet. + * + * @see SnippetTemplate#instantiationTimer + */ + private final DebugTimer instantiationTimer; + + /** + * Counts instantiations of all templates derived from this snippet. + * + * @see SnippetTemplate#instantiationCounter + */ private final DebugMetric instantiationCounter; - private final DebugTimer instantiationTimer; /** * The parameter names, taken from the local variables table. Only used for assertion @@ -101,6 +116,17 @@ assert initNames(); } + private int templateCount; + + void notifyNewTemplate() { + templateCount++; + if (UseSnippetTemplateCache && templateCount > MaxTemplatesPerSnippet) { + PrintStream err = System.err; + err.printf("WARNING: Exceeded %d templates for snippet %s%n" + " Adjust maximum with %s system property%n", MaxTemplatesPerSnippet, format("%h.%n(%p)", method), + MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME); + } + } + private boolean initNames() { int slotIdx = 0; for (int i = 0; i < names.length; i++) { @@ -332,8 +358,14 @@ } } - private static final DebugTimer SnippetCreationAndSpecialization = Debug.timer("SnippetCreationAndSpecialization"); - private static final DebugMetric SnippetSpecializations = Debug.metric("SnippetSpecializations"); + private static final DebugTimer SnippetTemplateCreationTime = Debug.timer("SnippetTemplateCreationTime"); + private static final DebugMetric SnippetTemplates = Debug.metric("SnippetTemplateCount"); + private static final DebugMetric SnippetTemplatesNodeCount = Debug.metric("SnippetTemplatesNodeCount"); + private static final DebugMetric SnippetGraphsNodeCount = Debug.metric("SnippetGraphsNodeCount"); + + private static final String MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME = "graal.maxTemplatesPerSnippet"; + private static final boolean UseSnippetTemplateCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetTemplateCache", "true")); + private static final int MaxTemplatesPerSnippet = Integer.getInteger(MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME, 50); /** * Base class for snippet classes. It provides a cache for {@link SnippetTemplate}s. @@ -347,7 +379,11 @@ protected AbstractTemplates(Providers providers, TargetDescription target) { this.providers = providers; this.target = target; - this.templates = new ConcurrentHashMap<>(); + if (UseSnippetTemplateCache) { + this.templates = new ConcurrentHashMap<>(); + } else { + this.templates = null; + } } /** @@ -371,10 +407,10 @@ * Gets a template for a given key, creating it first if necessary. */ protected SnippetTemplate template(final Arguments args) { - SnippetTemplate template = templates.get(args.cacheKey); + SnippetTemplate template = UseSnippetTemplateCache ? templates.get(args.cacheKey) : null; if (template == null) { - SnippetSpecializations.increment(); - try (TimerCloseable a = SnippetCreationAndSpecialization.start()) { + SnippetTemplates.increment(); + try (TimerCloseable a = SnippetTemplateCreationTime.start()) { template = Debug.scope("SnippetSpecialization", args.info.method, new Callable() { @Override @@ -382,7 +418,9 @@ return new SnippetTemplate(providers, args); } }); - templates.put(args.cacheKey, template); + if (UseSnippetTemplateCache) { + templates.put(args.cacheKey, template); + } } } return template; @@ -404,11 +442,39 @@ return false; } + private static String debugValueName(String category, Arguments args) { + if (Debug.isEnabled()) { + StringBuilder result = new StringBuilder(category).append('['); + SnippetInfo info = args.info; + result.append(info.method.getName()).append('('); + String sep = ""; + for (int i = 0; i < info.getParameterCount(); i++) { + if (info.isConstantParameter(i)) { + result.append(sep); + if (info.names[i] != null) { + result.append(info.names[i]); + } else { + result.append(i); + } + result.append('=').append(args.values[i]); + sep = ", "; + } + } + result.append(")]"); + return result.toString(); + + } + return null; + } + /** * Creates a snippet template. */ protected SnippetTemplate(final Providers providers, Arguments args) { StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method); + SnippetGraphsNodeCount.add(snippetGraph.getNodeCount()); + instantiationTimer = Debug.timer(debugValueName("SnippetTemplateInstantiationTime", args)); + instantiationCounter = Debug.metric(debugValueName("SnippetTemplateInstantiationCount", args)); ResolvedJavaMethod method = snippetGraph.method(); Signature signature = method.getSignature(); @@ -507,7 +573,7 @@ LoopBeginNode loopBegin = explodeLoop.findLoopBegin(); if (loopBegin != null) { LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); - int mark = snippetCopy.getMark(); + Mark mark = snippetCopy.getMark(); LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase(true)); new CanonicalizerPhase(true).applyIncremental(snippetCopy, phaseContext, mark); } @@ -596,6 +662,9 @@ this.deoptNodes = curDeoptNodes; this.stampNodes = curStampNodes; this.returnNode = retNode; + + SnippetTemplatesNodeCount.add(nodes.size()); + args.info.notifyNewTemplate(); } private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, VarargsPlaceholderNode[] placeholders) { @@ -676,6 +745,20 @@ private MemoryMapNode memoryMap; /** + * Times instantiations of this template. + * + * @see SnippetInfo#instantiationTimer + */ + private final DebugTimer instantiationTimer; + + /** + * Counts instantiations of this template. + * + * @see SnippetInfo#instantiationCounter + */ + private final DebugMetric instantiationCounter; + + /** * Gets the instantiation-time bindings to this template's parameters. * * @return the map that will be used to bind arguments to parameters when inlining this template @@ -783,7 +866,7 @@ return; } for (Node usage : newNode.usages().snapshot()) { - if (usage instanceof FloatingReadNode && ((FloatingReadNode) usage).lastLocationAccess() == newNode) { + if (usage instanceof FloatingReadNode && ((FloatingReadNode) usage).getLastLocationAccess() == newNode) { assert newNode.graph().isAfterFloatingReadPhase(); // lastLocationAccess points into the snippet graph. find a proper @@ -878,14 +961,15 @@ */ public Map instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args) { assert checkSnippetKills(replacee); - try (TimerCloseable a = args.info.instantiationTimer.start()) { + try (TimerCloseable a = args.info.instantiationTimer.start(); TimerCloseable b = instantiationTimer.start()) { args.info.instantiationCounter.increment(); + instantiationCounter.increment(); // Inline the snippet nodes, replacing parameters with the given args in the process StartNode entryPointNode = snippet.start(); FixedNode firstCFGNode = entryPointNode.next(); StructuredGraph replaceeGraph = replacee.graph(); IdentityHashMap replacements = bind(replaceeGraph, metaAccess, args); - replacements.put(entryPointNode, replaceeGraph.start()); + replacements.put(entryPointNode, BeginNode.prevBegin(replacee)); Map duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements); Debug.dump(replaceeGraph, "After inlining snippet %s", snippet.method()); @@ -973,6 +1057,7 @@ assert checkSnippetKills(replacee); try (TimerCloseable a = args.info.instantiationTimer.start()) { args.info.instantiationCounter.increment(); + instantiationCounter.increment(); // Inline the snippet nodes, replacing parameters with the given args in the process String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; @@ -981,7 +1066,7 @@ FixedNode firstCFGNode = entryPointNode.next(); StructuredGraph replaceeGraph = replacee.graph(); IdentityHashMap replacements = bind(replaceeGraph, metaAccess, args); - replacements.put(entryPointNode, replaceeGraph.start()); + replacements.put(entryPointNode, tool.getCurrentGuardAnchor().asNode()); Map duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements); Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Sat Nov 09 21:34:07 2013 +0100 @@ -38,7 +38,7 @@ public ReverseBytesNode(ValueNode value) { super(StampFactory.forKind(value.kind())); - assert kind().getStackKind() == Kind.Int || kind() == Kind.Long; + assert kind().isNumericInteger(); this.value = value; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationPolicy.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationPolicy.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationPolicy.java Sat Nov 09 21:34:07 2013 +0100 @@ -22,96 +22,8 @@ */ package com.oracle.graal.truffle; -import static com.oracle.graal.truffle.TruffleCompilerOptions.*; - -public class CompilationPolicy { - - private int invokeCounter; - private int originalInvokeCounter; - private int loopAndInvokeCounter; - private long prevTimestamp; - - private final int compilationThreshold; - private final String name; - - public CompilationPolicy(final int compilationThreshold, final int initialInvokeCounter, final String name) { - this.invokeCounter = initialInvokeCounter; - this.loopAndInvokeCounter = compilationThreshold; - this.originalInvokeCounter = compilationThreshold; - this.prevTimestamp = System.nanoTime(); - - this.compilationThreshold = compilationThreshold; - this.name = name; - } - - public String getName() { - return this.name; - } - - public int getInvokeCounter() { - return invokeCounter; - } - - public int getOriginalInvokeCounter() { - return originalInvokeCounter; - } - - public int getLoopAndInvokeCounter() { - return loopAndInvokeCounter; - } - - public void compilationInvalidated() { - int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue(); - invokeCounter = invalidationReprofileCount; - if (TruffleFunctionInlining.getValue()) { - originalInvokeCounter += invalidationReprofileCount; - } - } +public interface CompilationPolicy { - public void countInterpreterCall() { - invokeCounter--; - loopAndInvokeCounter--; - } - - public void inlined(int minInvokesAfterInlining) { - invokeCounter = minInvokesAfterInlining; - int inliningReprofileCount = TruffleInliningReprofileCount.getValue(); - loopAndInvokeCounter = inliningReprofileCount; - originalInvokeCounter = inliningReprofileCount; - } - - public void reportLoopCount(int count) { - loopAndInvokeCounter = Math.max(0, loopAndInvokeCounter - count); - } - - public void nodeReplaced() { - // delay compilation until tree is deemed stable enough - int replaceBackoff = TruffleReplaceReprofileCount.getValue(); - if (loopAndInvokeCounter < replaceBackoff) { - loopAndInvokeCounter = replaceBackoff; - } - } + boolean shouldCompile(CompilationProfile profile); - public boolean compileOrInline() { - if (invokeCounter <= 0 && loopAndInvokeCounter <= 0) { - if (TruffleUseTimeForCompilationDecision.getValue()) { - long timestamp = System.nanoTime(); - long timespan = (timestamp - prevTimestamp); - if (timespan < (TruffleCompilationDecisionTime.getValue())) { - return true; - } - this.loopAndInvokeCounter = compilationThreshold; - this.originalInvokeCounter = compilationThreshold; - this.prevTimestamp = timestamp; - if (TruffleCompilationDecisionTimePrintFail.getValue()) { - // Checkstyle: stop - System.out.println(name + ": timespan " + (timespan / 1000000) + " ms larger than threshold"); - // Checkstyle: resume - } - } else { - return true; - } - } - return false; - } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,125 @@ +/* + * 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.truffle; + +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; + +public class CompilationProfile { + + private static final int MIN_INVOKES_AFTER_INLINING = 2; + + private int invokeCounter; + private int originalInvokeCounter; + private int loopAndInvokeCounter; + /** + * Number of times an installed code for this tree was invalidated. + */ + private int invalidationCount; + + /** + * Number of times a node was replaced in this tree. + */ + private int nodeReplaceCount; + + private long previousTimestamp; + + private final int compilationThreshold; + private final String name; + + public CompilationProfile(final int compilationThreshold, final int initialInvokeCounter, final String name) { + this.invokeCounter = initialInvokeCounter; + this.loopAndInvokeCounter = compilationThreshold; + this.originalInvokeCounter = compilationThreshold; + this.previousTimestamp = System.nanoTime(); + + this.compilationThreshold = compilationThreshold; + this.name = name; + } + + public long getPreviousTimestamp() { + return previousTimestamp; + } + + public String getName() { + return this.name; + } + + public int getInvalidationCount() { + return invalidationCount; + } + + public int getNodeReplaceCount() { + return nodeReplaceCount; + } + + public int getInvokeCounter() { + return invokeCounter; + } + + public int getOriginalInvokeCounter() { + return originalInvokeCounter; + } + + public int getLoopAndInvokeCounter() { + return loopAndInvokeCounter; + } + + void reportTiminingFailed(long timestamp) { + this.loopAndInvokeCounter = compilationThreshold; + this.originalInvokeCounter = compilationThreshold; + this.previousTimestamp = timestamp; + } + + void reportInvalidated() { + invalidationCount++; + int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue(); + invokeCounter = invalidationReprofileCount; + originalInvokeCounter += invalidationReprofileCount; + } + + void reportInterpreterCall() { + invokeCounter--; + loopAndInvokeCounter--; + } + + void reportInliningPerformed() { + invokeCounter = MIN_INVOKES_AFTER_INLINING; + int inliningReprofileCount = TruffleInliningReprofileCount.getValue(); + loopAndInvokeCounter = inliningReprofileCount; + originalInvokeCounter = inliningReprofileCount; + } + + void reportLoopCount(int count) { + loopAndInvokeCounter = Math.max(0, loopAndInvokeCounter - count); + } + + void reportNodeReplaced() { + nodeReplaceCount++; + // delay compilation until tree is deemed stable enough + int replaceBackoff = TruffleReplaceReprofileCount.getValue(); + if (loopAndInvokeCounter < replaceBackoff) { + loopAndInvokeCounter = replaceBackoff; + } + } + +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultCompilationPolicy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultCompilationPolicy.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,31 @@ +/* + * 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.truffle; + +public class DefaultCompilationPolicy implements CompilationPolicy { + + public boolean shouldCompile(CompilationProfile profile) { + return profile.getInvokeCounter() <= 0 && profile.getLoopAndInvokeCounter() <= 0; + } + +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Sat Nov 09 21:34:07 2013 +0100 @@ -41,36 +41,35 @@ public final class OptimizedCallTarget extends DefaultCallTarget implements FrameFactory, LoopCountReceiver, ReplaceObserver { private static final PrintStream OUT = TTY.out().out(); - private static final int MIN_INVOKES_AFTER_INLINING = 2; + + private InstalledCode installedCode; + private Future installedCodeTask; + private final TruffleCompiler compiler; + private final CompilationProfile compilationProfile; + private final CompilationPolicy compilationPolicy; + private final TruffleInlining inlining; + private boolean compilationEnabled; + private int callCount; protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int invokeCounter, int compilationThreshold) { super(rootNode, descriptor); this.compiler = compiler; - this.compilationPolicy = new CompilationPolicy(compilationThreshold, invokeCounter, rootNode.toString()); + this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); + this.inlining = new TruffleInliningImpl(); this.rootNode.setCallTarget(this); + if (TruffleUseTimeForCompilationDecision.getValue()) { + compilationPolicy = new TimedCompilationPolicy(); + } else { + compilationPolicy = new DefaultCompilationPolicy(); + } + this.compilationEnabled = true; + if (TruffleCallTargetProfiling.getValue()) { registerCallTarget(this); } } - private InstalledCode installedCode; - private Future installedCodeTask; - private final TruffleCompiler compiler; - private final CompilationPolicy compilationPolicy; - private boolean disableCompilation; - private int callCount; - - /** - * Number of times an installed code for this tree was invalidated. - */ - private int invalidationCount; - - /** - * Number of times a node was replaced in this tree. - */ - private int nodeReplaceCount; - @Override public Object call(PackedFrame caller, Arguments args) { return callHelper(caller, args); @@ -99,6 +98,10 @@ } } + public CompilationProfile getCompilationProfile() { + return compilationProfile; + } + private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { invalidate(); return call(caller, args); @@ -109,10 +112,10 @@ if (m != null) { CompilerAsserts.neverPartOfCompilation(); installedCode = null; - invalidationCount++; - compilationPolicy.compilationInvalidated(); + compilationProfile.reportInvalidated(); if (TraceTruffleCompilation.getValue()) { - OUT.printf("[truffle] invalidated %-48s |Inv# %d |Replace# %d\n", rootNode, invalidationCount, nodeReplaceCount); + OUT.printf("[truffle] invalidated %-48s |Inv# %d |Replace# %d\n", rootNode, compilationProfile.getInvalidationCount(), + compilationProfile.getNodeReplaceCount()); } } @@ -120,50 +123,63 @@ if (task != null) { task.cancel(true); this.installedCodeTask = null; - compilationPolicy.compilationInvalidated(); + compilationProfile.reportInvalidated(); } } private Object interpreterCall(PackedFrame caller, Arguments args) { CompilerAsserts.neverPartOfCompilation(); - compilationPolicy.countInterpreterCall(); - if (disableCompilation || !compilationPolicy.compileOrInline()) { - return executeHelper(caller, args); - } else { - return compileOrInline(caller, args); + compilationProfile.reportInterpreterCall(); + if (compilationEnabled && shouldCompile()) { + if (isCompiling()) { + return waitForCompilation(caller, args); + } + boolean inlined = shouldInline() && inline(); + if (!inlined) { + compile(); + } + } + return executeHelper(caller, args); + } + + private boolean shouldCompile() { + return compilationPolicy.shouldCompile(compilationProfile); + } + + private static boolean shouldInline() { + return TruffleFunctionInlining.getValue(); + } + + private boolean isCompiling() { + if (installedCodeTask != null) { + if (installedCodeTask.isCancelled()) { + installedCodeTask = null; + return false; + } + return true; + } + return false; + } + + public void compile() { + this.installedCodeTask = compiler.compile(this); + if (!TruffleBackgroundCompilation.getValue()) { + installedCode = receiveInstalledCode(); } } - private Object compileOrInline(PackedFrame caller, Arguments args) { - if (installedCodeTask != null) { - // There is already a compilation running. - if (installedCodeTask.isCancelled()) { - installedCodeTask = null; - } else { - if (installedCodeTask.isDone()) { - receiveInstalledCode(); - } - return executeHelper(caller, args); - } + private Object waitForCompilation(PackedFrame caller, Arguments args) { + if (installedCodeTask.isDone()) { + installedCode = receiveInstalledCode(); } - - if (TruffleFunctionInlining.getValue() && inline()) { - compilationPolicy.inlined(MIN_INVOKES_AFTER_INLINING); - return call(caller, args); - } else { - compile(); - return executeHelper(caller, args); - } + return executeHelper(caller, args); } - private void receiveInstalledCode() { + private InstalledCode receiveInstalledCode() { try { - this.installedCode = installedCodeTask.get(); - if (TruffleCallTargetProfiling.getValue()) { - resetProfiling(); - } + return installedCodeTask.get(); } catch (InterruptedException | ExecutionException e) { - disableCompilation = true; + compilationEnabled = false; OUT.printf("[truffle] opt failed %-48s %s\n", rootNode, e.getMessage()); if (e.getCause() instanceof BailoutException) { // Bailout => move on. @@ -175,21 +191,21 @@ System.exit(-1); } } + return null; } - installedCodeTask = null; } + /** + * Forces inlining whether or not function inlining is enabled. + * + * @return true if an inlining was performed + */ public boolean inline() { - CompilerAsserts.neverPartOfCompilation(); - return new InliningHelper(this).inline(); - } - - public void compile() { - CompilerAsserts.neverPartOfCompilation(); - this.installedCodeTask = compiler.compile(this); - if (!TruffleBackgroundCompilation.getValue()) { - receiveInstalledCode(); + boolean result = inlining.performInlining(this); + if (result) { + compilationProfile.reportInliningPerformed(); } + return result; } public Object executeHelper(PackedFrame caller, Arguments args) { @@ -208,198 +224,13 @@ @Override public void reportLoopCount(int count) { - compilationPolicy.reportLoopCount(count); + compilationProfile.reportLoopCount(count); } @Override public void nodeReplaced() { - nodeReplaceCount++; + compilationProfile.reportNodeReplaced(); invalidate(); - compilationPolicy.nodeReplaced(); - } - - private static class InliningHelper { - - private final OptimizedCallTarget target; - - public InliningHelper(OptimizedCallTarget target) { - this.target = target; - } - - public boolean inline() { - final InliningPolicy policy = new InliningPolicy(target); - if (!policy.continueInlining()) { - if (TraceTruffleInliningDetails.getValue()) { - List inlinableCallSites = getInlinableCallSites(target); - if (!inlinableCallSites.isEmpty()) { - OUT.printf("[truffle] inlining hit caller size limit (%3d >= %3d).%3d remaining call sites in %s:\n", policy.callerNodeCount, TruffleInliningMaxCallerSize.getValue(), - inlinableCallSites.size(), target.getRootNode()); - policy.sortByRelevance(inlinableCallSites); - printCallSiteInfo(policy, inlinableCallSites, ""); - } - } - return false; - } - - List inlinableCallSites = getInlinableCallSites(target); - if (inlinableCallSites.isEmpty()) { - return false; - } - - policy.sortByRelevance(inlinableCallSites); - - boolean inlined = false; - for (InlinableCallSiteInfo inlinableCallSite : inlinableCallSites) { - if (!policy.isWorthInlining(inlinableCallSite)) { - break; - } - if (inlinableCallSite.getCallSite().inline(target)) { - if (TraceTruffleInlining.getValue()) { - printCallSiteInfo(policy, inlinableCallSite, "inlined"); - } - inlined = true; - break; - } - } - - if (inlined) { - for (InlinableCallSiteInfo callSite : inlinableCallSites) { - callSite.getCallSite().resetCallCount(); - } - } else { - if (TraceTruffleInliningDetails.getValue()) { - OUT.printf("[truffle] inlining stopped.%3d remaining call sites in %s:\n", inlinableCallSites.size(), target.getRootNode()); - printCallSiteInfo(policy, inlinableCallSites, ""); - } - } - - return inlined; - } - - private static void printCallSiteInfo(InliningPolicy policy, List inlinableCallSites, String msg) { - for (InlinableCallSiteInfo candidate : inlinableCallSites) { - printCallSiteInfo(policy, candidate, msg); - } - } - - private static void printCallSiteInfo(InliningPolicy policy, InlinableCallSiteInfo callSite, String msg) { - String calls = String.format("%4s/%4s", callSite.getCallCount(), policy.callerInvocationCount); - String nodes = String.format("%3s/%3s", callSite.getInlineNodeCount(), policy.callerNodeCount); - OUT.printf("[truffle] %-9s %-50s |Nodes %6s |Calls %6s %7.3f |%s\n", msg, callSite.getCallSite(), nodes, calls, policy.metric(callSite), callSite.getCallSite().getCallTarget()); - } - - private static final class InliningPolicy { - - private final int callerNodeCount; - private final int callerInvocationCount; - - public InliningPolicy(OptimizedCallTarget caller) { - this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode()); - this.callerInvocationCount = caller.compilationPolicy.getOriginalInvokeCounter(); - } - - public boolean continueInlining() { - return callerNodeCount < TruffleInliningMaxCallerSize.getValue(); - } - - public boolean isWorthInlining(InlinableCallSiteInfo callSite) { - return callSite.getInlineNodeCount() <= TruffleInliningMaxCalleeSize.getValue() && callSite.getInlineNodeCount() + callerNodeCount <= TruffleInliningMaxCallerSize.getValue() && - callSite.getCallCount() > 0 && callSite.getRecursiveDepth() < TruffleInliningMaxRecursiveDepth.getValue() && - (frequency(callSite) >= TruffleInliningMinFrequency.getValue() || callSite.getInlineNodeCount() <= TruffleInliningTrivialSize.getValue()); - } - - public double metric(InlinableCallSiteInfo callSite) { - double cost = callSite.getInlineNodeCount(); - double metric = frequency(callSite) / cost; - return metric; - } - - private double frequency(InlinableCallSiteInfo callSite) { - return (double) callSite.getCallCount() / (double) callerInvocationCount; - } - - public void sortByRelevance(List inlinableCallSites) { - Collections.sort(inlinableCallSites, new Comparator() { - - @Override - public int compare(InlinableCallSiteInfo cs1, InlinableCallSiteInfo cs2) { - int result = (isWorthInlining(cs2) ? 1 : 0) - (isWorthInlining(cs1) ? 1 : 0); - if (result == 0) { - return Double.compare(metric(cs2), metric(cs1)); - } - return result; - } - }); - } - } - - private static final class InlinableCallSiteInfo { - - private final InlinableCallSite callSite; - private final int callCount; - private final int nodeCount; - private final int recursiveDepth; - - public InlinableCallSiteInfo(InlinableCallSite callSite) { - this.callSite = callSite; - this.callCount = callSite.getCallCount(); - this.nodeCount = NodeUtil.countNodes(callSite.getInlineTree()); - this.recursiveDepth = calculateRecursiveDepth(); - } - - public int getRecursiveDepth() { - return recursiveDepth; - } - - private int calculateRecursiveDepth() { - int depth = 0; - Node parent = ((Node) callSite).getParent(); - while (!(parent instanceof RootNode)) { - assert parent != null; - if (parent instanceof InlinedCallSite && ((InlinedCallSite) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; - } - parent = parent.getParent(); - } - if (((RootNode) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; - } - return depth; - } - - public InlinableCallSite getCallSite() { - return callSite; - } - - public int getCallCount() { - return callCount; - } - - public int getInlineNodeCount() { - return nodeCount; - } - } - - private static List getInlinableCallSites(final DefaultCallTarget target) { - final ArrayList inlinableCallSites = new ArrayList<>(); - target.getRootNode().accept(new NodeVisitor() { - - @Override - public boolean visit(Node node) { - if (node instanceof InlinableCallSite) { - inlinableCallSites.add(new InlinableCallSiteInfo((InlinableCallSite) node)); - } - return true; - } - }); - return inlinableCallSites; - } - } - - private static void resetProfiling() { - for (OptimizedCallTarget callTarget : OptimizedCallTarget.callTargets.keySet()) { - callTarget.callCount = 0; - } } private static void printProfiling() { @@ -425,19 +256,19 @@ continue; } - int notInlinedCallSiteCount = InliningHelper.getInlinableCallSites(callTarget).size(); + int notInlinedCallSiteCount = TruffleInliningImpl.getInlinableCallSites(callTarget).size(); int nodeCount = NodeUtil.countNodes(callTarget.rootNode); int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.rootNode, InlinedCallSite.class); String comment = callTarget.installedCode == null ? " int" : ""; - comment += callTarget.disableCompilation ? " fail" : ""; + comment += callTarget.compilationEnabled ? "" : " fail"; OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, - callTarget.invalidationCount, comment); + callTarget.getCompilationProfile().getInvalidationCount(), comment); totalCallCount += callTarget.callCount; totalInlinedCallSiteCount += inlinedCallSiteCount; totalNotInlinedCallSiteCount += notInlinedCallSiteCount; totalNodeCount += nodeCount; - totalInvalidationCount += callTarget.invalidationCount; + totalInvalidationCount += callTarget.getCompilationProfile().getInvalidationCount(); } OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount, totalInvalidationCount); } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Sat Nov 09 21:34:07 2013 +0100 @@ -34,6 +34,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.Node; import com.oracle.graal.graph.spi.*; import com.oracle.graal.java.*; @@ -211,7 +212,7 @@ if (inlineGraph != null) { int nodeCountBefore = graph.getNodeCount(); - int mark = graph.getMark(); + Mark mark = graph.getMark(); InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false); if (Debug.isDumpEnabled()) { int nodeCountAfter = graph.getNodeCount(); diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TimedCompilationPolicy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TimedCompilationPolicy.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle; + +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; + +public class TimedCompilationPolicy extends DefaultCompilationPolicy { + + @Override + public boolean shouldCompile(CompilationProfile profile) { + if (super.shouldCompile(profile)) { + long timestamp = System.nanoTime(); + long prevTimestamp = profile.getPreviousTimestamp(); + long timespan = (timestamp - prevTimestamp); + if (timespan < (TruffleCompilationDecisionTime.getValue())) { + return true; + } + // TODO shouldCompile should not modify the compilation profile + // maybe introduce another method? + profile.reportTiminingFailed(timestamp); + if (TruffleCompilationDecisionTimePrintFail.getValue()) { + // Checkstyle: stop + System.out.println(profile.getName() + ": timespan " + (timespan / 1000000) + " ms larger than threshold"); + // Checkstyle: resume + } + } + return false; + } + +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Sat Nov 09 21:34:07 2013 +0100 @@ -32,6 +32,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.Node; import com.oracle.graal.graph.spi.*; import com.oracle.graal.java.*; @@ -114,7 +115,7 @@ CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!AOTCompilation.getValue()); PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase); - int mark = 0; + Mark mark = null; while (true) { partialEscapePhase.apply(graph, phaseContext); @@ -128,7 +129,7 @@ boolean inliningProgress = false; for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) { - if (graph.getMark() != mark) { + if (graph.getMark().equals(mark)) { // Make sure macro substitutions such as // CompilerDirectives.transferToInterpreter get processed first. for (Node newNode : graph.getNewNodes(mark)) { @@ -153,7 +154,7 @@ } } List argumentSnapshot = methodCallTarget.arguments().snapshot(); - int beforeInvokeMark = graph.getMark(); + Mark beforeInvokeMark = graph.getMark(); expandInvoke(methodCallTarget); for (Node arg : argumentSnapshot) { if (arg != null && arg.recordsUsages()) { diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Sat Nov 09 21:34:07 2013 +0100 @@ -160,12 +160,16 @@ if (compiledMethod == null) { throw new BailoutException("Could not install method, code cache is full!"); } + if (!compiledMethod.isValid()) { + return null; + } if (TraceTruffleCompilation.getValue()) { int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode()); - OUT.printf("[truffle] optimized %-50s %d |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", compilable.getRootNode(), compilable.hashCode(), nodeCountTruffle, + byte[] code = compiledMethod.getCode(); + OUT.printf("[truffle] optimized %-50s %x |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", compilable.getRootNode(), compilable.hashCode(), nodeCountTruffle, (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, - (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, compiledMethod.getCode().length); + (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, code != null ? code.length : 0); } return compiledMethod; } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,28 @@ +/* + * 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.truffle; + +public interface TruffleInlining { + + boolean performInlining(OptimizedCallTarget callTarget); +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Sat Nov 09 21:34:07 2013 +0100 @@ -0,0 +1,207 @@ +/* + * 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.truffle; + +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; + +import java.io.*; +import java.util.*; + +import com.oracle.graal.debug.*; +import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.nodes.*; + +class TruffleInliningImpl implements TruffleInlining { + + private static final PrintStream OUT = TTY.out().out(); + + @Override + public boolean performInlining(OptimizedCallTarget target) { + final InliningPolicy policy = new InliningPolicy(target); + if (!policy.continueInlining()) { + if (TraceTruffleInliningDetails.getValue()) { + List inlinableCallSites = getInlinableCallSites(target); + if (!inlinableCallSites.isEmpty()) { + OUT.printf("[truffle] inlining hit caller size limit (%3d >= %3d).%3d remaining call sites in %s:\n", policy.callerNodeCount, TruffleInliningMaxCallerSize.getValue(), + inlinableCallSites.size(), target.getRootNode()); + policy.sortByRelevance(inlinableCallSites); + printCallSiteInfo(policy, inlinableCallSites, ""); + } + } + return false; + } + + List inlinableCallSites = getInlinableCallSites(target); + if (inlinableCallSites.isEmpty()) { + return false; + } + + policy.sortByRelevance(inlinableCallSites); + + boolean inlined = false; + for (InlinableCallSiteInfo inlinableCallSite : inlinableCallSites) { + if (!policy.isWorthInlining(inlinableCallSite)) { + break; + } + if (inlinableCallSite.getCallSite().inline(target)) { + if (TraceTruffleInlining.getValue()) { + printCallSiteInfo(policy, inlinableCallSite, "inlined"); + } + inlined = true; + break; + } + } + + if (inlined) { + for (InlinableCallSiteInfo callSite : inlinableCallSites) { + callSite.getCallSite().resetCallCount(); + } + } else { + if (TraceTruffleInliningDetails.getValue()) { + OUT.printf("[truffle] inlining stopped.%3d remaining call sites in %s:\n", inlinableCallSites.size(), target.getRootNode()); + printCallSiteInfo(policy, inlinableCallSites, ""); + } + } + + return inlined; + } + + private static void printCallSiteInfo(InliningPolicy policy, List inlinableCallSites, String msg) { + for (InlinableCallSiteInfo candidate : inlinableCallSites) { + printCallSiteInfo(policy, candidate, msg); + } + } + + private static void printCallSiteInfo(InliningPolicy policy, InlinableCallSiteInfo callSite, String msg) { + String calls = String.format("%4s/%4s", callSite.getCallCount(), policy.callerInvocationCount); + String nodes = String.format("%3s/%3s", callSite.getInlineNodeCount(), policy.callerNodeCount); + OUT.printf("[truffle] %-9s %-50s |Nodes %6s |Calls %6s %7.3f |%s\n", msg, callSite.getCallSite(), nodes, calls, policy.metric(callSite), callSite.getCallSite().getCallTarget()); + } + + private static final class InliningPolicy { + + private final int callerNodeCount; + private final int callerInvocationCount; + + public InliningPolicy(OptimizedCallTarget caller) { + this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode()); + this.callerInvocationCount = caller.getCompilationProfile().getOriginalInvokeCounter(); + } + + public boolean continueInlining() { + return callerNodeCount < TruffleInliningMaxCallerSize.getValue(); + } + + public boolean isWorthInlining(InlinableCallSiteInfo callSite) { + return callSite.getInlineNodeCount() <= TruffleInliningMaxCalleeSize.getValue() && callSite.getInlineNodeCount() + callerNodeCount <= TruffleInliningMaxCallerSize.getValue() && + callSite.getCallCount() > 0 && callSite.getRecursiveDepth() < TruffleInliningMaxRecursiveDepth.getValue() && + (frequency(callSite) >= TruffleInliningMinFrequency.getValue() || callSite.getInlineNodeCount() <= TruffleInliningTrivialSize.getValue()); + } + + public double metric(InlinableCallSiteInfo callSite) { + double cost = callSite.getInlineNodeCount(); + double metric = frequency(callSite) / cost; + return metric; + } + + private double frequency(InlinableCallSiteInfo callSite) { + return (double) callSite.getCallCount() / (double) callerInvocationCount; + } + + public void sortByRelevance(List inlinableCallSites) { + Collections.sort(inlinableCallSites, new Comparator() { + + @Override + public int compare(InlinableCallSiteInfo cs1, InlinableCallSiteInfo cs2) { + int result = (isWorthInlining(cs2) ? 1 : 0) - (isWorthInlining(cs1) ? 1 : 0); + if (result == 0) { + return Double.compare(metric(cs2), metric(cs1)); + } + return result; + } + }); + } + } + + private static final class InlinableCallSiteInfo { + + private final InlinableCallSite callSite; + private final int callCount; + private final int nodeCount; + private final int recursiveDepth; + + public InlinableCallSiteInfo(InlinableCallSite callSite) { + this.callSite = callSite; + this.callCount = callSite.getCallCount(); + this.nodeCount = NodeUtil.countNodes(callSite.getInlineTree()); + this.recursiveDepth = calculateRecursiveDepth(); + } + + public int getRecursiveDepth() { + return recursiveDepth; + } + + private int calculateRecursiveDepth() { + int depth = 0; + Node parent = ((Node) callSite).getParent(); + while (!(parent instanceof RootNode)) { + assert parent != null; + if (parent instanceof InlinedCallSite && ((InlinedCallSite) parent).getCallTarget() == callSite.getCallTarget()) { + depth++; + } + parent = parent.getParent(); + } + if (((RootNode) parent).getCallTarget() == callSite.getCallTarget()) { + depth++; + } + return depth; + } + + public InlinableCallSite getCallSite() { + return callSite; + } + + public int getCallCount() { + return callCount; + } + + public int getInlineNodeCount() { + return nodeCount; + } + } + + static List getInlinableCallSites(final DefaultCallTarget target) { + final ArrayList inlinableCallSites = new ArrayList<>(); + target.getRootNode().accept(new NodeVisitor() { + + @Override + public boolean visit(Node node) { + if (node instanceof InlinableCallSite) { + inlinableCallSites.add(new InlinableCallSiteInfo((InlinableCallSite) node)); + } + return true; + } + }); + return inlinableCallSites; + } +} diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java Sat Nov 09 21:34:07 2013 +0100 @@ -25,17 +25,37 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.truffle.*; -public class AssumptionValidAssumption extends Assumptions.Assumption { +public final class AssumptionValidAssumption extends Assumptions.Assumption { private static final long serialVersionUID = 2010244979610891262L; - private OptimizedAssumption assumption; + private final OptimizedAssumption assumption; public AssumptionValidAssumption(OptimizedAssumption assumption) { this.assumption = assumption; + assert assumption != null; } public OptimizedAssumption getAssumption() { return assumption; } + + @Override + public int hashCode() { + return 31 + assumption.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AssumptionValidAssumption) { + AssumptionValidAssumption other = (AssumptionValidAssumption) obj; + return other.assumption == this.assumption; + } + return false; + } + + @Override + public String toString() { + return assumption.toString(); + } } diff -r ad2434911b69 -r a5b5e1ebab81 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Sat Nov 09 21:33:31 2013 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Sat Nov 09 21:34:07 2013 +0100 @@ -24,6 +24,7 @@ */ package com.oracle.truffle.api.nodes; +import java.io.*; import java.lang.annotation.*; import java.util.*; @@ -184,6 +185,7 @@ if (!NodeUtil.replaceChild(this.parent, this, newNode)) { fixupTree(); } + reportReplace(); return newNode; } @@ -193,7 +195,7 @@ * This is a rather expensive operation but rare to occur. */ private void fixupTree() { - Node rootNode = NodeUtil.findParent(this, RootNode.class); + Node rootNode = getRootNode(); if (rootNode == null) { throw new UnsupportedOperationException("Tree does not have a root node."); } @@ -243,6 +245,15 @@ return false; } + private void reportReplace() { + RootNode rootNode = getRootNode(); + if (rootNode != null) { + if (rootNode.getCallTarget() instanceof ReplaceObserver) { + ((ReplaceObserver) rootNode.getCallTarget()).nodeReplaced(); + } + } + } + /** * Intended to be implemented by subclasses of {@link Node} to receive a notification when the * node is rewritten. This method is invoked before the actual replace has happened. @@ -251,37 +262,34 @@ * @param reason the reason the replace supplied */ protected void onReplace(Node newNode, String reason) { - RootNode rootNode = NodeUtil.findParent(this, RootNode.class); - if (rootNode != null) { - if (rootNode.getCallTarget() instanceof ReplaceObserver) { - ((ReplaceObserver) rootNode.getCallTarget()).nodeReplaced(); + if (TruffleOptions.TraceRewrites) { + traceRewrite(newNode, reason); + } + } + + private void traceRewrite(Node newNode, String reason) { + Class from = getClass(); + Class to = newNode.getClass(); + + if (TruffleOptions.TraceRewritesFilterFromKind != null) { + if (filterByKind(from, TruffleOptions.TraceRewritesFilterFromKind)) { + return; } } - if (TruffleOptions.TraceRewrites) { - Class from = getClass(); - Class to = newNode.getClass(); - if (TruffleOptions.TraceRewritesFilterFromKind != null) { - if (filterByKind(from, TruffleOptions.TraceRewritesFilterFromKind)) { - return; - } - } - - if (TruffleOptions.TraceRewritesFilterToKind != null) { - if (filterByKind(to, TruffleOptions.TraceRewritesFilterToKind)) { - return; - } - } - - String filter = TruffleOptions.TraceRewritesFilterClass; - if (filter != null && (filterByContainsClassName(from, filter) || filterByContainsClassName(to, filter))) { + if (TruffleOptions.TraceRewritesFilterToKind != null) { + if (filterByKind(to, TruffleOptions.TraceRewritesFilterToKind)) { return; } + } - // CheckStyle: stop system..print check - System.out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(from), formatNodeInfo(to), reason); - // CheckStyle: resume system..print check + String filter = TruffleOptions.TraceRewritesFilterClass; + if (filter != null && (filterByContainsClassName(from, filter) || filterByContainsClassName(to, filter))) { + return; } + + PrintStream out = System.out; + out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(from), formatNodeInfo(to), reason); } private static String formatNodeInfo(Class clazz) { @@ -383,6 +391,23 @@ } /** + * Get the root node of the tree a node belongs to. + * + * @return the {@link RootNode} or {@code null} if there is none. + */ + protected final RootNode getRootNode() { + Node rootNode = this; + while (rootNode.getParent() != null) { + assert !(rootNode instanceof RootNode) : "root node must not have a parent"; + rootNode = rootNode.getParent(); + } + if (rootNode instanceof RootNode) { + return (RootNode) rootNode; + } + return null; + } + + /** * Converts this node to a textual representation useful for debugging. */ @Override diff -r ad2434911b69 -r a5b5e1ebab81 mx/commands.py --- a/mx/commands.py Sat Nov 09 21:33:31 2013 +0100 +++ b/mx/commands.py Sat Nov 09 21:34:07 2013 +0100 @@ -1331,11 +1331,8 @@ mx.run_java(['-jar', jacocoreport.get_path(True), '-in', 'jacoco.exec', '-g', join(_graal_home, 'graal'), out]) def sl(args): - """run an SL program - - VM args should have a @ prefix.""" - vmArgs = [a[1:] for a in args if a[0] == '@'] - slArgs = [a for a in args if a[0] != '@'] + """run an SL program""" + vmArgs, slArgs = _extract_VM_args(args) vm(vmArgs + ['-cp', mx.classpath("com.oracle.truffle.sl"), "com.oracle.truffle.sl.SimpleLanguage"] + slArgs) def isGraalEnabled(vm): diff -r ad2434911b69 -r a5b5e1ebab81 mxtool/mx.py --- a/mxtool/mx.py Sat Nov 09 21:33:31 2013 +0100 +++ b/mxtool/mx.py Sat Nov 09 21:34:07 2013 +0100 @@ -1425,34 +1425,28 @@ else: preexec_fn = os.setsid - if not callable(out) and not callable(err) and timeout is None: - # The preexec_fn=os.setsid - p = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec_fn, creationflags=creationflags, env=env) - _currentSubprocess = (p, args) + def redirect(stream, f): + for line in iter(stream.readline, ''): + f(line) + stream.close() + stdout = out if not callable(out) else subprocess.PIPE + stderr = err if not callable(err) else subprocess.PIPE + p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, creationflags=creationflags, env=env) + _currentSubprocess = (p, args) + if callable(out): + t = Thread(target=redirect, args=(p.stdout, out)) + t.daemon = True # thread dies with the program + t.start() + if callable(err): + t = Thread(target=redirect, args=(p.stderr, err)) + t.daemon = True # thread dies with the program + t.start() + if timeout is None or timeout == 0: retcode = waitOn(p) else: - def redirect(stream, f): - for line in iter(stream.readline, ''): - f(line) - stream.close() - stdout = out if not callable(out) else subprocess.PIPE - stderr = err if not callable(err) else subprocess.PIPE - p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, creationflags=creationflags, env=env) - _currentSubprocess = (p, args) - if callable(out): - t = Thread(target=redirect, args=(p.stdout, out)) - t.daemon = True # thread dies with the program - t.start() - if callable(err): - t = Thread(target=redirect, args=(p.stderr, err)) - t.daemon = True # thread dies with the program - t.start() - if timeout is None or timeout == 0: - retcode = waitOn(p) - else: - if get_os() == 'windows': - abort('Use of timeout not (yet) supported on Windows') - retcode = _waitWithTimeout(p, args, timeout) + if get_os() == 'windows': + abort('Use of timeout not (yet) supported on Windows') + retcode = _waitWithTimeout(p, args, timeout) except OSError as e: log('Error executing \'' + ' '.join(args) + '\': ' + str(e)) if _opts.verbose: @@ -2983,10 +2977,10 @@ # The path should always be p.name/dir. independent of where the workspace actually is. # So we use the parent folder of the project, whatever that is, to generate such a relative path. logicalWorkspaceRoot = os.path.dirname(p.dir) - binFolder = os.path.relpath(p.output_dir(), logicalWorkspaceRoot) - + binFolder = os.path.relpath(p.output_dir(), logicalWorkspaceRoot) + if _isAnnotationProcessorDependency(p): - refreshFile = os.path.relpath(join(p.dir, p.name + '.jar'), logicalWorkspaceRoot) + refreshFile = os.path.relpath(join(p.dir, p.name + '.jar'), logicalWorkspaceRoot) _genEclipseBuilder(out, p, 'Jar', 'archive ' + p.name, refresh=True, refreshFile=refreshFile, relevantResources=[binFolder], async=True, xmlIndent='', xmlStandalone='no') if projToDist.has_key(p.name): @@ -3068,18 +3062,18 @@ refreshScope = '${project}' else: refreshScope = '${working_set:}' - - launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_RECURSIVE', 'value': 'false'}) + + launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_RECURSIVE', 'value': 'false'}) launchOut.element('stringAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE', 'value': refreshScope}) if relevantResources is not None: resources = '${working_set:' for relevantResource in relevantResources: - resources += '' + resources += '' resources += '}' launchOut.element('stringAttribute', {'key' : 'org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE', 'value': resources}) - - + + launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON', 'value': consoleOn}) launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND', 'value': 'true' if async else 'false'}) if logToFile: diff -r ad2434911b69 -r a5b5e1ebab81 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Sat Nov 09 21:33:31 2013 +0100 +++ b/src/share/vm/code/nmethod.cpp Sat Nov 09 21:34:07 2013 +0100 @@ -229,6 +229,7 @@ #ifdef GRAAL static java_nmethod_stats_struct graal_java_nmethod_stats; #endif +static java_nmethod_stats_struct unknwon_java_nmethod_stats; static native_nmethod_stats_struct native_nmethod_stats; static pc_nmethod_stats_struct pc_nmethod_stats; @@ -237,18 +238,21 @@ #ifdef COMPILER1 if (nm->is_compiled_by_c1()) { c1_java_nmethod_stats.note_nmethod(nm); - } + } else #endif #ifdef COMPILER2 if (nm->is_compiled_by_c2()) { c2_java_nmethod_stats.note_nmethod(nm); - } + } else #endif #ifdef GRAAL if (nm->is_compiled_by_graal()) { graal_java_nmethod_stats.note_nmethod(nm); + } else +#endif + { + unknwon_java_nmethod_stats.note_nmethod(nm); } -#endif } @@ -3087,6 +3091,7 @@ #ifdef GRAAL graal_java_nmethod_stats.print_nmethod_stats("Graal"); #endif + unknwon_java_nmethod_stats.print_nmethod_stats("Unknown"); DebugInformationRecorder::print_statistics(); pc_nmethod_stats.print_pc_stats(); Dependencies::print_statistics(); diff -r ad2434911b69 -r a5b5e1ebab81 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Sat Nov 09 21:33:31 2013 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Sat Nov 09 21:34:07 2013 +0100 @@ -1339,6 +1339,9 @@ DeoptReason reason = trap_request_reason(trap_request); DeoptAction action = trap_request_action(trap_request); +#ifdef GRAAL + short speculation_id = trap_request_speculation_id(trap_request); +#endif jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1 vframe* vf = vframe::new_vframe(&fr, ®_map, thread); @@ -1349,7 +1352,11 @@ ScopeDesc* trap_scope = cvf->scope(); if (TraceDeoptimization) { - tty->print_cr(" bci=%d pc=%d, relative_pc=%d, method=%s", trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name()->as_C_string()); + tty->print_cr(" bci=%d pc=%d, relative_pc=%d, method=%s" GRAAL_ONLY(", speculation=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name()->as_C_string() +#ifdef GRAAL + , speculation_id +#endif + ); } methodHandle trap_method = trap_scope->method(); @@ -1460,12 +1467,16 @@ tty->print(" (Graal: no installed code) "); } #endif //GRAAL - tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d", + tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d" GRAAL_ONLY(" speculation=%d"), fr.pc(), os::current_thread_id(), trap_reason_name(reason), trap_action_name(action), - unloaded_class_index); + unloaded_class_index +#ifdef GRAAL + , speculation_id +#endif + ); if (class_name != NULL) { tty->print(unresolved ? " unresolved class: " : " symbol: "); class_name->print_symbol_on(tty); @@ -1970,13 +1981,24 @@ jint unloaded_class_index = trap_request_index(trap_request); const char* reason = trap_reason_name(trap_request_reason(trap_request)); const char* action = trap_action_name(trap_request_action(trap_request)); +#ifdef GRAAL + short speculation_id = trap_request_speculation_id(trap_request); +#endif size_t len; if (unloaded_class_index < 0) { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s'", - reason, action); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s'" GRAAL_ONLY(" speculation='%d'"), + reason, action +#ifdef GRAAL + ,speculation_id +#endif + ); } else { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'", - reason, action, unloaded_class_index); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'" GRAAL_ONLY(" speculation='%d'"), + reason, action, unloaded_class_index +#ifdef GRAAL + ,speculation_id +#endif + ); } if (len >= buflen) buf[buflen-1] = '\0'; diff -r ad2434911b69 -r a5b5e1ebab81 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Sat Nov 09 21:33:31 2013 +0100 +++ b/src/share/vm/runtime/deoptimization.hpp Sat Nov 09 21:34:07 2013 +0100 @@ -102,8 +102,10 @@ enum { _action_bits = 3, _reason_bits = 5, + _speculation_id_bits = 16, _action_shift = 0, _reason_shift = _action_shift+_action_bits, + _speculation_id_shift = _reason_shift+_reason_bits, BC_CASE_LIMIT = PRODUCT_ONLY(1) NOT_PRODUCT(4) // for _deoptimization_hist }; @@ -286,6 +288,14 @@ // standard action for unloaded CP entry return _unloaded_action; } + static short trap_request_speculation_id(int trap_request) { + if (trap_request < 0) + return (DeoptAction) + ((~(trap_request) >> _speculation_id_shift) & right_n_bits(_speculation_id_bits)); + else + // standard action for unloaded CP entry + return 0; + } static int trap_request_index(int trap_request) { if (trap_request < 0) return -1;