# HG changeset patch # User Doug Simon # Date 1426765626 -3600 # Node ID 812fc403db8c85637facfaf2500ad409b9ba0080 # Parent e018185695f63701ae44954baec6714fa7175bab# Parent c39d8bafd342c2597d9426793627ae3b23423277 Merge. diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Thu Mar 19 12:47:06 2015 +0100 @@ -39,6 +39,9 @@ * patched. */ private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0); + private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g1), new ScratchRegister(g3)}; + // Points to the next free scratch register + private int nextFreeScratchRegister = 0; public SPARCMacroAssembler(TargetDescription target, RegisterConfig registerConfig) { super(target, registerConfig); @@ -389,4 +392,26 @@ public void signx(Register rd) { sra(rd, g0, rd); } + + public ScratchRegister getScratchRegister() { + return scratchRegister[nextFreeScratchRegister++]; + } + + public class ScratchRegister implements AutoCloseable { + private final Register register; + + public ScratchRegister(Register register) { + super(); + this.register = register; + } + + public Register getRegister() { + return register; + } + + public void close() { + assert nextFreeScratchRegister > 0 : "Close called too often"; + nextFreeScratchRegister--; + } + } } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Thu Mar 19 12:47:06 2015 +0100 @@ -298,9 +298,6 @@ public static final OptionValue OptFloatingReads = new OptionValue<>(true); @Option(help = "", type = OptionType.Debug) - public static final OptionValue OptTailDuplication = new OptionValue<>(false); - - @Option(help = "", type = OptionType.Debug) public static final OptionValue OptEliminatePartiallyRedundantGuards = new OptionValue<>(true); @Option(help = "", type = OptionType.Debug) diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java Thu Mar 19 12:47:06 2015 +0100 @@ -47,6 +47,7 @@ public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) { super(bits, OPS); assert bits == 64 || (bits == 32 && (Double.isNaN(lowerBound) || (float) lowerBound == lowerBound) && (Double.isNaN(upperBound) || (float) upperBound == upperBound)); + assert Double.isNaN(lowerBound) == Double.isNaN(upperBound); this.lowerBound = lowerBound; this.upperBound = upperBound; this.nonNaN = nonNaN; @@ -130,6 +131,10 @@ return nonNaN; } + public boolean isNaN() { + return Double.isNaN(lowerBound); + } + public boolean isUnrestricted() { return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN; } @@ -629,6 +634,9 @@ @Override public Stamp foldStamp(Stamp s) { FloatStamp stamp = (FloatStamp) s; + if (stamp.isNaN()) { + return stamp; + } return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN()); } }, @@ -666,8 +674,19 @@ @Override public Stamp foldStamp(Stamp stamp) { - assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 32; - return StampFactory.forKind(Kind.Int); + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 32; + boolean mustHaveZero = !floatStamp.isNonNaN(); + int lowerBound = (int) floatStamp.lowerBound(); + int upperBound = (int) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(Kind.Int, lowerBound, upperBound); } }, @@ -681,8 +700,19 @@ @Override public Stamp foldStamp(Stamp stamp) { - assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 32; - return StampFactory.forKind(Kind.Long); + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 32; + boolean mustHaveZero = !floatStamp.isNonNaN(); + long lowerBound = (long) floatStamp.lowerBound(); + long upperBound = (long) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(Kind.Long, lowerBound, upperBound); } }, @@ -696,8 +726,19 @@ @Override public Stamp foldStamp(Stamp stamp) { - assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 64; - return StampFactory.forKind(Kind.Int); + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 64; + boolean mustHaveZero = !floatStamp.isNonNaN(); + int lowerBound = (int) floatStamp.lowerBound(); + int upperBound = (int) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(Kind.Int, lowerBound, upperBound); } }, @@ -711,8 +752,19 @@ @Override public Stamp foldStamp(Stamp stamp) { - assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 64; - return StampFactory.forKind(Kind.Long); + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 64; + boolean mustHaveZero = !floatStamp.isNonNaN(); + long lowerBound = (long) floatStamp.lowerBound(); + long upperBound = (long) floatStamp.upperBound(); + if (mustHaveZero) { + if (lowerBound > 0) { + lowerBound = 0; + } else if (upperBound < 0) { + upperBound = 0; + } + } + return StampFactory.forInteger(Kind.Long, lowerBound, upperBound); } }, @@ -726,8 +778,9 @@ @Override public Stamp foldStamp(Stamp stamp) { - assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 32; - return StampFactory.forKind(Kind.Double); + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 32; + return StampFactory.forFloat(Kind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN()); } }, @@ -741,8 +794,9 @@ @Override public Stamp foldStamp(Stamp stamp) { - assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 64; - return StampFactory.forKind(Kind.Float); + FloatStamp floatStamp = (FloatStamp) stamp; + assert floatStamp.getBits() == 64; + return StampFactory.forFloat(Kind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN()); } }); } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java Thu Mar 19 12:47:06 2015 +0100 @@ -973,7 +973,9 @@ public Stamp foldStamp(Stamp input) { IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 32; - return StampFactory.forKind(Kind.Float); + float lowerBound = stamp.lowerBound(); + float upperBound = stamp.upperBound(); + return StampFactory.forFloat(Kind.Float, lowerBound, upperBound, true); } }, @@ -989,7 +991,9 @@ public Stamp foldStamp(Stamp input) { IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 64; - return StampFactory.forKind(Kind.Float); + float lowerBound = stamp.lowerBound(); + float upperBound = stamp.upperBound(); + return StampFactory.forFloat(Kind.Float, lowerBound, upperBound, true); } }, @@ -1005,7 +1009,9 @@ public Stamp foldStamp(Stamp input) { IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 32; - return StampFactory.forKind(Kind.Double); + double lowerBound = stamp.lowerBound(); + double upperBound = stamp.upperBound(); + return StampFactory.forFloat(Kind.Double, lowerBound, upperBound, true); } }, @@ -1021,7 +1027,9 @@ public Stamp foldStamp(Stamp input) { IntegerStamp stamp = (IntegerStamp) input; assert stamp.getBits() == 64; - return StampFactory.forKind(Kind.Double); + double lowerBound = stamp.lowerBound(); + double upperBound = stamp.upperBound(); + return StampFactory.forFloat(Kind.Double, lowerBound, upperBound, true); } }); } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Thu Mar 19 12:47:06 2015 +0100 @@ -75,10 +75,6 @@ appendPhase(new LoopFullUnrollPhase(canonicalizer)); } - if (OptTailDuplication.getValue()) { - appendPhase(new TailDuplicationPhase(canonicalizer)); - } - if (PartialEscapeAnalysis.getValue()) { appendPhase(new PartialEscapePhase(true, canonicalizer)); } diff -r e018185695f6 -r 812fc403db8c 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 Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Thu Mar 19 12:47:06 2015 +0100 @@ -847,12 +847,19 @@ protected void afterClone(@SuppressWarnings("unused") Node other) { } + public boolean verifyInputs() { + for (Node input : inputs()) { + assertFalse(input.isDeleted(), "input was deleted"); + assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph"); + assertTrue(input.usages().contains(this), "missing usage in input %s", input); + } + return true; + } + public boolean verify() { assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id); assertTrue(graph() != null, "null graph"); - for (Node input : inputs()) { - assertTrue(input.usages().contains(this), "missing usage in input %s", input); - } + verifyInputs(); for (Node successor : successors()) { assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor()); assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor); @@ -864,7 +871,7 @@ while (iterator.hasNext()) { Position pos = iterator.nextPosition(); if (pos.get(usage) == this && pos.getInputType() != InputType.Unchecked) { - assert isAllowedUsageType(pos.getInputType()) : "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")"; + assertTrue(isAllowedUsageType(pos.getInputType()), "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")"); } } } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Thu Mar 19 12:47:06 2015 +0100 @@ -26,7 +26,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; /** @@ -60,15 +59,15 @@ boolean isIntrinsic(); } - T append(T fixed); - - T append(T fixed); + T append(T value); - T append(T fixed); - - T append(T value); - - T append(T value); + /** + * Adds the given floating node to the graph and also adds recursively all referenced inputs. + * + * @param value the floating node to be added to the graph + * @return either the node added or an equivalent node + */ + T recursiveAppend(T value); StampProvider getStampProvider(); diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Thu Mar 19 12:47:06 2015 +0100 @@ -222,10 +222,10 @@ */ private InvocationPlugins parent; - private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess, int estimatePluginCount) { + private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) { this.registrationThread = Thread.currentThread(); this.metaAccess = metaAccess; - this.registrations = new ArrayList<>(estimatePluginCount); + this.registrations = new ArrayList<>(INITIAL_PLUGIN_CAPACITY); InvocationPlugins p = parent; // Only adopt a non-empty parent while (p != null && p.size() == 0) { @@ -234,21 +234,17 @@ this.parent = p; } - private static final int DEFAULT_ESTIMATE_PLUGIN_COUNT = 16; + private static final int INITIAL_PLUGIN_CAPACITY = 64; /** * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}. */ public InvocationPlugins(InvocationPlugins parent) { - this(parent, parent.metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT); + this(parent, parent.metaAccess); } public InvocationPlugins(MetaAccessProvider metaAccess) { - this(metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT); - } - - public InvocationPlugins(MetaAccessProvider metaAccess, int estimatePluginCount) { - this(null, metaAccess, estimatePluginCount); + this(null, metaAccess); } /** diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Thu Mar 19 12:47:06 2015 +0100 @@ -38,6 +38,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.hotspot.*; @@ -52,7 +53,6 @@ import com.oracle.graal.lir.sparc.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.sparc.*; /** * HotSpot SPARC specific backend. @@ -113,7 +113,7 @@ if (SPARCAssembler.isSimm13(address.getDisplacement())) { masm.stx(g0, address); } else { - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); new Setx(address.getDisplacement(), scratch).emit(masm); masm.stx(g0, new SPARCAddress(sp, scratch)); @@ -148,7 +148,7 @@ if (SPARCAssembler.isSimm13(stackpoinerChange)) { masm.save(sp, stackpoinerChange, sp); } else { - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); new Setx(stackpoinerChange, scratch).emit(masm); masm.save(sp, scratch, sp); @@ -227,7 +227,7 @@ CallingConvention cc = regConfig.getCallingConvention(JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false); Register inlineCacheKlass = g5; // see MacroAssembler::ic_call - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); Register receiver = asRegister(cc.getArgument(0)); SPARCAddress src = new SPARCAddress(receiver, config.hubOffset); @@ -261,7 +261,7 @@ if (unverifiedStub != null) { masm.bind(unverifiedStub); - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER)); } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java Thu Mar 19 12:47:06 2015 +0100 @@ -27,6 +27,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.*; @@ -36,19 +37,12 @@ public class SPARCHotSpotCounterOp extends HotSpotCounterOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class); - @Temp({OperandFlag.REG}) private AllocatableValue scratch0; - @Temp({OperandFlag.REG}) private AllocatableValue scratch1; - - public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue scratch0, AllocatableValue scratch1) { + public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) { super(TYPE, name, group, increment, registers, config); - this.scratch0 = scratch0; - this.scratch1 = scratch1; } - public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue scratch0, AllocatableValue scratch1) { + public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) { super(TYPE, names, groups, increments, registers, config); - this.scratch0 = scratch0; - this.scratch1 = scratch1; } @Override @@ -58,27 +52,32 @@ // address for counters array SPARCAddress countersArrayAddr = new SPARCAddress(thread, config.graalCountersThreadOffset); - Register countersArrayReg = asRegister(scratch0); + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register countersArrayReg = scratch.getRegister(); - // load counters array - masm.ldx(countersArrayAddr, countersArrayReg); + // load counters array + masm.ldx(countersArrayAddr, countersArrayReg); - forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment)); + forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment)); + } } private void emitIncrement(SPARCMacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) { // address for counter SPARCAddress counterAddr = new SPARCAddress(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment))); - Register counterReg = asRegister(scratch1); - // load counter value - masm.ldx(counterAddr, counterReg); - // increment counter - if (isConstant(increment)) { - masm.add(counterReg, asInt(asConstant(increment)), counterReg); - } else { - masm.add(counterReg, asRegister(increment), counterReg); + + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register counterReg = scratch.getRegister(); + // load counter value + masm.ldx(counterAddr, counterReg); + // increment counter + if (isConstant(increment)) { + masm.add(counterReg, asInt(asConstant(increment)), counterReg); + } else { + masm.add(counterReg, asRegister(increment), counterReg); + } + // store counter value + masm.stx(counterReg, counterAddr); } - // store counter value - masm.stx(counterReg, counterAddr); } } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java Thu Mar 19 12:47:06 2015 +0100 @@ -26,10 +26,10 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.sparc.*; -import com.oracle.graal.sparc.*; /** * Removes the current frame and tail calls the uncommon trap routine. @@ -52,7 +52,7 @@ // HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub); // frameContext.enter(crb); - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER)); } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java Thu Mar 19 12:47:06 2015 +0100 @@ -31,9 +31,9 @@ import com.oracle.graal.asm.sparc.*; import com.oracle.graal.asm.sparc.SPARCAssembler.CC; import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; -import com.oracle.graal.sparc.*; /** * Sets up the arguments for an exception handler in the callers frame, removes the current frame @@ -69,7 +69,7 @@ // Restore SP from L7 if the exception PC is a method handle call site. SPARCAddress dst = new SPARCAddress(thread, isMethodHandleReturnOffset); - try (SPARCScratchRegister scratch = SPARCScratchRegister.get()) { + try (ScratchRegister scratch = masm.getScratchRegister()) { Register scratchReg = scratch.getRegister(); masm.lduw(dst, scratchReg); masm.cmp(scratchReg, scratchReg); diff -r e018185695f6 -r 812fc403db8c 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 Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Thu Mar 19 12:47:06 2015 +0100 @@ -49,7 +49,6 @@ import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp; import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp; import com.oracle.graal.lir.sparc.SPARCMove.StoreOp; -import com.oracle.graal.sparc.*; public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator { @@ -368,28 +367,18 @@ @Override public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) { if (BenchmarkCounters.enabled) { - try (SPARCScratchRegister sc0 = SPARCScratchRegister.get()) { - RegisterValue scratch0 = sc0.getRegister().asValue(getLIRKindTool().getWordKind()); - try (SPARCScratchRegister sc1 = SPARCScratchRegister.get()) { - RegisterValue scratch1 = sc1.getRegister().asValue(getLIRKindTool().getWordKind()); - return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, scratch0, scratch1); - } - } + return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config); + } else { + return null; } - return null; } @Override public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) { if (BenchmarkCounters.enabled) { - try (SPARCScratchRegister sc0 = SPARCScratchRegister.get()) { - RegisterValue scratch0 = sc0.getRegister().asValue(getLIRKindTool().getWordKind()); - try (SPARCScratchRegister sc1 = SPARCScratchRegister.get()) { - RegisterValue scratch1 = sc1.getRegister().asValue(getLIRKindTool().getWordKind()); - return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, scratch0, scratch1); - } - } + return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config); + } else { + return null; } - return null; } } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Thu Mar 19 12:47:06 2015 +0100 @@ -85,6 +85,8 @@ " dacapo = 'err, starting =====, PASSED in'%n" + " specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'", type = OptionType.Debug) private static final OptionValue BenchmarkDynamicCounters = new OptionValue<>(null); + @Option(help = "Use grouping separators for number printing", type = OptionType.Debug) + private static final OptionValue DynamicCountersPrintGroupSeparator = new OptionValue<>(true); //@formatter:on } @@ -207,28 +209,29 @@ cnt--; } + String numFmt = Options.DynamicCountersPrintGroupSeparator.getValue() ? "%,19d" : "%19d"; if (staticCounter) { out.println("=========== " + group + " (static counters):"); for (Map.Entry entry : sorted.entrySet()) { long counter = entry.getKey() / array.length; - out.format(Locale.US, "%,19d %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); + out.format(Locale.US, numFmt + " %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); } - out.format(Locale.US, "%,19d total\n", sum); + out.format(Locale.US, numFmt + " total\n", sum); } else { if (group.startsWith("~")) { out.println("=========== " + group + " (dynamic counters), time = " + seconds + " s:"); for (Map.Entry entry : sorted.entrySet()) { long counter = entry.getKey() / array.length; - out.format(Locale.US, "%,19d/s %3d%% %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue()); + out.format(Locale.US, numFmt + "/s %3d%% %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue()); } - out.format(Locale.US, "%,19d/s total\n", (long) (sum / seconds)); + out.format(Locale.US, numFmt + "/s total\n", (long) (sum / seconds)); } else { out.println("=========== " + group + " (dynamic counters):"); for (Map.Entry entry : sorted.entrySet()) { long counter = entry.getKey() / array.length; - out.format(Locale.US, "%,19d %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); + out.format(Locale.US, numFmt + " %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); } - out.format(Locale.US, "%,19d total\n", sum); + out.format(Locale.US, numFmt + " total\n", sum); } } } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Thu Mar 19 12:47:06 2015 +0100 @@ -109,15 +109,15 @@ } else if (n instanceof CheckCastDynamicNode) { checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool); } else if (n instanceof InstanceOfNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage().areDeoptsFixed()) { instanceofSnippets.lower((InstanceOfNode) n, tool); } } else if (n instanceof InstanceOfDynamicNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage().areDeoptsFixed()) { instanceofSnippets.lower((InstanceOfDynamicNode) n, tool); } } else if (n instanceof ClassIsAssignableFromNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage().areDeoptsFixed()) { instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool); } } else if (n instanceof NewInstanceNode) { diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Thu Mar 19 12:47:06 2015 +0100 @@ -28,6 +28,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; +import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; @@ -49,8 +50,6 @@ */ public class HotSpotGraphBuilderPlugins { - private static final int PLUGIN_COUNT_ESTIMATE = 160; - /** * Creates a {@link Plugins} object that should be used when running on HotSpot. * @@ -61,8 +60,7 @@ */ public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements, Architecture arch) { - - InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, PLUGIN_COUNT_ESTIMATE); + InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess); Plugins plugins = new Plugins(invocationPlugins); NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider); @@ -80,9 +78,6 @@ registerStableOptionPlugins(invocationPlugins); StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, arch, invocationPlugins, !config.useHeapProfiler); - int size = invocationPlugins.size(); - assert PLUGIN_COUNT_ESTIMATE >= size : String.format("adjust %s.PLUGIN_COUNT_ESTIMATE to be above or equal to %d", HotSpotGraphBuilderPlugins.class.getSimpleName(), size); - assert PLUGIN_COUNT_ESTIMATE - size < 20 : String.format("adjust %s.PLUGIN_COUNT_ESTIMATE to be closer to %d", HotSpotGraphBuilderPlugins.class.getSimpleName(), size); return plugins; } @@ -92,7 +87,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) { ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp(); ValueNode mirror; - if (objectStamp.isExactType() && objectStamp.nonNull()) { + if (objectStamp.isExactType() && objectStamp.nonNull() && !GraalOptions.ImmutableCode.getValue()) { mirror = b.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess())); } else { StampProvider stampProvider = b.getStampProvider(); diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Thu Mar 19 12:47:06 2015 +0100 @@ -38,8 +38,8 @@ final class HotSpotInvocationPlugins extends InvocationPlugins { final HotSpotVMConfig config; - public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, int estimatePluginCount) { - super(metaAccess, estimatePluginCount); + public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) { + super(metaAccess); this.config = config; } diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java Thu Mar 19 12:47:06 2015 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.hotspot.meta.*; @@ -53,7 +54,7 @@ @Override public Node canonical(CanonicalizerTool tool) { ValueNode javaClass = getJavaClass(); - if (javaClass.isConstant()) { + if (javaClass.isConstant() && !GraalOptions.ImmutableCode.getValue()) { HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant(); JavaConstant classLoader = c.getClassLoader(); if (classLoader != null) { diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Thu Mar 19 12:47:06 2015 +0100 @@ -76,6 +76,7 @@ } LoopTransformations.peel(osrLoop); + osr.replaceAtUsages(InputType.Guard, AbstractBeginNode.prevBegin((FixedNode) osr.predecessor())); for (Node usage : osr.usages().snapshot()) { ProxyNode proxy = (ProxyNode) usage; proxy.replaceAndDelete(proxy.value()); @@ -107,6 +108,8 @@ assert value == null || value instanceof OSRLocalNode; } } + osr.replaceAtUsages(InputType.Guard, osrStart); + assert osr.usages().isEmpty(); GraphUtil.killCFG(start); diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Thu Mar 19 12:47:06 2015 +0100 @@ -1033,7 +1033,7 @@ protected abstract ValueNode appendConstant(JavaConstant constant); - protected abstract ValueNode append(ValueNode v); + protected abstract T append(T v); protected boolean isNeverExecutedCode(double probability) { return probability == 0 && optimisticOpts.removeNeverExecutedCode(); diff -r e018185695f6 -r 812fc403db8c 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 Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Mar 19 12:47:06 2015 +0100 @@ -1487,61 +1487,41 @@ return ConstantNode.forConstant(constant, metaAccess, currentGraph); } - @SuppressWarnings("unchecked") @Override - public ValueNode append(ValueNode v) { + public T append(T v) { if (v.graph() != null) { - // This node was already appended to the graph. return v; } - if (v instanceof ControlSinkNode) { - return append((ControlSinkNode) v); - } - if (v instanceof ControlSplitNode) { - return append((ControlSplitNode) v); - } - if (v instanceof FixedWithNextNode) { - return append((FixedWithNextNode) v); + T added = currentGraph.addOrUnique(v); + if (added == v) { + updateLastInstruction(v); } - if (v instanceof FloatingNode) { - return append((FloatingNode) v); - } - throw GraalInternalError.shouldNotReachHere("Can not append Node of type: " + v.getClass().getName()); - } - - public T append(T fixed) { - assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - T added = currentGraph.add(fixed); - lastInstr.setNext(added); - lastInstr = null; return added; } - public T append(T fixed) { - assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - T added = currentGraph.add(fixed); - lastInstr.setNext(added); - lastInstr = null; + public T recursiveAppend(T v) { + if (v.graph() != null) { + return v; + } + T added = currentGraph.addOrUniqueWithInputs(v); + if (added == v) { + updateLastInstruction(v); + } return added; } - public T append(T fixed) { - assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - T added = currentGraph.add(fixed); - lastInstr.setNext(added); - lastInstr = added; - return added; - } - - public T append(T v) { - if (v.graph() != null) { - return v; + private void updateLastInstruction(T v) { + if (v instanceof FixedNode) { + FixedNode fixedNode = (FixedNode) v; + lastInstr.setNext(fixedNode); + if (fixedNode instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; + assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; + lastInstr = fixedWithNextNode; + } else { + lastInstr = null; + } } - T added = currentGraph.unique(v); - return added; } private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) { diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Thu Mar 19 12:47:06 2015 +0100 @@ -37,7 +37,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; @@ -371,7 +371,7 @@ masm.mulx(asIntReg(src1), asIntReg(src2), asIntReg(dst)); break; case IMULCC: - try (SPARCScratchRegister tmpScratch = SPARCScratchRegister.get()) { + try (ScratchRegister tmpScratch = masm.getScratchRegister()) { Register tmp = tmpScratch.getRegister(); masm.mulx(asIntReg(src1), asIntReg(src2), asIntReg(dst)); Label noOverflow = new Label(); diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Thu Mar 19 12:47:06 2015 +0100 @@ -39,6 +39,7 @@ import com.oracle.graal.asm.sparc.SPARCAssembler.BranchPredict; import com.oracle.graal.asm.sparc.SPARCAssembler.CC; import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; @@ -47,7 +48,6 @@ import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure; import com.oracle.graal.lir.asm.*; import com.oracle.graal.sparc.SPARC.CPUFeature; -import com.oracle.graal.sparc.*; public class SPARCControlFlow { @@ -219,21 +219,14 @@ actualConditionFlag = actualConditionFlag.mirror(); } boolean isValidConstant = isConstant(actualY) && isSimm5(asConstant(actualY)); - SPARCScratchRegister scratch = null; - try { + try (ScratchRegister scratch = masm.getScratchRegister()) { if (isConstant(actualY) && !isValidConstant) { // Make sure, the y value is loaded - scratch = SPARCScratchRegister.get(); Value scratchValue = scratch.getRegister().asValue(actualY.getLIRKind()); SPARCMove.move(crb, masm, scratchValue, actualY, SPARCDelayedControlTransfer.DUMMY); actualY = scratchValue; } emitCBCond(masm, actualX, actualY, actualTrueTarget, actualConditionFlag); masm.nop(); - } finally { - if (scratch != null) { - // release the scratch if used - scratch.close(); - } } if (needJump) { masm.jmp(actualFalseTarget); @@ -481,14 +474,14 @@ if (isSimm13(lowKey)) { masm.sub(value, lowKey, scratchReg); } else { - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch2 = sc.getRegister(); new Setx(lowKey, scratch2).emit(masm); masm.sub(value, scratch2, scratchReg); } } int upperLimit = highKey - lowKey; - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch2 = sc.getRegister(); if (isSimm13(upperLimit)) { masm.cmp(scratchReg, upperLimit); diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Thu Mar 19 12:47:06 2015 +0100 @@ -31,7 +31,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; @@ -133,7 +133,7 @@ Kind inputKind = (Kind) input.getPlatformKind(); Kind resultKind = (Kind) result.getPlatformKind(); int resultKindSize = crb.target.getSizeInBytes(resultKind); - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); SPARCAddress tempAddress = generateSimm13OffsetLoad((SPARCAddress) crb.asAddress(temp), masm, scratch); switch (inputKind) { @@ -295,7 +295,7 @@ @Override public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); final SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); final Register dst = asRegister(result); @@ -495,7 +495,7 @@ @Override public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { assert isRegister(input); - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); delayedControlTransfer.emitControlTransfer(crb, masm); @@ -548,7 +548,7 @@ @Override public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); delayedControlTransfer.emitControlTransfer(crb, masm); @@ -604,7 +604,7 @@ if (constant.isDefaultForKind() || constant.isNull()) { reg2stack(crb, masm, result, g0.asValue(LIRKind.derive(input)), delaySlotLir); } else { - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); long value = constant.asLong(); if (isSimm13(value)) { @@ -681,7 +681,7 @@ private static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { SPARCAddress dst = (SPARCAddress) crb.asAddress(result); - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); dst = generateSimm13OffsetLoad(dst, masm, scratch); Register src = asRegister(input); @@ -716,7 +716,7 @@ private static void stack2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { SPARCAddress src = (SPARCAddress) crb.asAddress(input); - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); src = generateSimm13OffsetLoad(src, masm, scratch); Register dst = asRegister(result); @@ -752,7 +752,7 @@ } private static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) { - try (SPARCScratchRegister sc = SPARCScratchRegister.get()) { + try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); boolean hasVIS3 = ((SPARC) masm.target.arch).getFeatures().contains(CPUFeature.VIS3); switch (input.getKind().getStackKind()) { diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Thu Mar 19 12:47:06 2015 +0100 @@ -79,6 +79,10 @@ public boolean areFrameStatesAtSideEffects() { return !this.areFrameStatesAtDeopts(); } + + public boolean areDeoptsFixed() { + return this.ordinal() >= FIXED_DEOPTS.ordinal(); + } } /** diff -r e018185695f6 -r 812fc403db8c 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 Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Thu Mar 19 12:47:06 2015 +0100 @@ -249,6 +249,9 @@ return true; } else { customCanonicalizer.simplify(node, tool); + if (node.isDeleted()) { + return true; + } } } if (nodeClass.isCanonicalizable()) { @@ -260,7 +263,7 @@ canonical = ((BinaryCommutative) node).maybeCommuteInputs(); } } catch (Throwable e) { - throw Debug.handle(e); + throw new RuntimeException(e); } if (performReplacement(node, canonical)) { return true; diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java Thu Mar 19 12:47:06 2015 +0100 @@ -377,7 +377,7 @@ private void processConditionAnchor(ConditionAnchorNode node) { tryProofCondition(node.condition(), (guard, result) -> { - if (result == node.isNegated()) { + if (result != node.isNegated()) { node.replaceAtUsages(guard); GraphUtil.unlinkFixedNode(node); GraphUtil.killWithUnusedFloatingInputs(node); diff -r e018185695f6 -r 812fc403db8c 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 Thu Mar 19 12:46:38 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,575 +0,0 @@ -/* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.phases.common; - -import static com.oracle.graal.compiler.common.GraalOptions.*; - -import java.util.*; -import java.util.function.*; - -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.Graph.Mark; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.debug.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.tiers.*; - -/** - * This class is a phase that looks for opportunities for tail duplication. The static method - * {@link #tailDuplicate(AbstractMergeNode, TailDuplicationDecision, List, PhaseContext, CanonicalizerPhase)} - * can also be used to drive tail duplication from other places, e.g., inlining. - */ -public class TailDuplicationPhase extends BasePhase { - - /* - * Various metrics on the circumstances in which tail duplication was/wasn't performed. - */ - private static final DebugMetric metricDuplicationConsidered = Debug.metric("DuplicationConsidered"); - private static final DebugMetric metricDuplicationPerformed = Debug.metric("DuplicationPerformed"); - - private final CanonicalizerPhase canonicalizer; - - @NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor}) - static final class DummyAnchorNode extends FixedWithNextNode implements GuardingNode, AnchoringNode { - public static final NodeClass TYPE = NodeClass.create(DummyAnchorNode.class); - - public DummyAnchorNode() { - super(TYPE, StampFactory.forVoid()); - } - - } - - /** - * This interface is used by tail duplication to let clients decide if tail duplication should - * be performed. - */ - public interface TailDuplicationDecision { - - /** - * Queries if tail duplication should be performed at the given merge. If this method - * returns true then the tail duplication will be performed, because all other checks have - * happened before. - * - * @param merge The merge at which tail duplication can be performed. - * @param fixedNodeCount The size of the set of fixed nodes that forms the base for the - * duplicated set of nodes. - * @return true if the tail duplication should be performed, false otherwise. - */ - boolean doTransform(AbstractMergeNode merge, int fixedNodeCount); - } - - /** - * A tail duplication decision closure that employs the default algorithm: Check if there are - * any phis on the merge whose stamps improve and that have usages within the duplicated set of - * fixed nodes. - */ - public static final TailDuplicationDecision DEFAULT_DECISION = new TailDuplicationDecision() { - - public boolean doTransform(AbstractMergeNode merge, int fixedNodeCount) { - if (fixedNodeCount < TailDuplicationTrivialSize.getValue()) { - return true; - } - ArrayList improvements = null; - for (PhiNode phi : merge.phis()) { - Stamp phiStamp = phi.stamp(); - for (ValueNode input : phi.values()) { - if (!input.stamp().equals(phiStamp)) { - if (improvements == null) { - improvements = new ArrayList<>(); - } - if (!improvements.contains(phi)) { - improvements.add(phi); - } - break; - } - } - } - if (improvements == null) { - return false; - } - FixedNode current = merge; - int opportunities = 0; - while (current instanceof FixedWithNextNode) { - current = ((FixedWithNextNode) current).next(); - if (current instanceof VirtualizableAllocation) { - return false; - } - for (PhiNode phi : improvements) { - for (Node input : current.inputs()) { - if (input == phi) { - opportunities++; - } - if (input.inputs().contains(phi)) { - opportunities++; - } - } - } - } - return opportunities > 0; - } - }; - - /** - * A tail duplication decision closure that always returns true. - */ - public static final TailDuplicationDecision TRUE_DECISION = new TailDuplicationDecision() { - - @Override - public boolean doTransform(AbstractMergeNode merge, int fixedNodeCount) { - return true; - } - }; - - public TailDuplicationPhase(CanonicalizerPhase canonicalizer) { - this.canonicalizer = canonicalizer; - } - - @Override - protected void run(StructuredGraph graph, PhaseContext phaseContext) { - if (graph.hasNode(AbstractMergeNode.TYPE)) { - ToDoubleFunction nodeProbabilities = new FixedNodeProbabilityCache(); - - // A snapshot is taken here, so that new MergeNode instances aren't considered for tail - // duplication. - for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE).snapshot()) { - if (!(merge instanceof LoopBeginNode) && nodeProbabilities.applyAsDouble(merge) >= TailDuplicationProbability.getValue()) { - tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer); - } - } - } - } - - /** - * This method attempts to duplicate the tail of the given merge. The merge must not be a - * {@link LoopBeginNode}. If the merge is eligible for duplication (at least one fixed node in - * its tail, no {@link MonitorEnterNode}/ {@link MonitorExitNode}, non-null - * {@link AbstractMergeNode#stateAfter()}) then the decision callback is used to determine - * whether the tail duplication should actually be performed. If replacements is non-null, then - * this list of {@link PiNode}s is used to replace one value per merge end. - * - * @param merge The merge whose tail should be duplicated. - * @param decision A callback that can make the final decision if tail duplication should occur - * or not. - * @param replacements A list of {@link PiNode}s, or null. If this list is non-null then its - * size needs to match the merge's end count. Each entry can either be null or a - * {@link PiNode}, and is used to replace {@link PiNode#object()} with the - * {@link PiNode} in the duplicated branch that corresponds to the entry. - * @param phaseContext - */ - public static boolean tailDuplicate(AbstractMergeNode merge, TailDuplicationDecision decision, List replacements, PhaseContext phaseContext, CanonicalizerPhase canonicalizer) { - assert !(merge instanceof LoopBeginNode); - assert replacements == null || replacements.size() == merge.forwardEndCount(); - FixedNode fixed = merge; - int fixedCount = 0; - while (fixed instanceof FixedWithNextNode) { - fixed = ((FixedWithNextNode) fixed).next(); - if (fixed instanceof CommitAllocationNode || fixed instanceof ControlFlowAnchorNode) { - return false; - } - fixedCount++; - } - if (fixedCount > 1) { - metricDuplicationConsidered.increment(); - if (decision.doTransform(merge, fixedCount)) { - metricDuplicationPerformed.increment(); - new DuplicationOperation(merge, replacements, canonicalizer).duplicate(phaseContext); - return true; - } - } - return false; - } - - /** - * This class encapsulates one tail duplication operation on a specific - * {@link AbstractMergeNode}. - */ - private static class DuplicationOperation { - - private final AbstractMergeNode merge; - private final StructuredGraph graph; - - private final Map bottomPhis = Node.newMap(); - private final List replacements; - - private final CanonicalizerPhase canonicalizer; - - /** - * Initializes the tail duplication operation without actually performing any work. - * - * @param merge The merge whose tail should be duplicated. - * @param replacements A list of replacement {@link PiNode}s, or null. If this is non-null, - * then the size of the list needs to match the number of end nodes at the merge. - */ - public DuplicationOperation(AbstractMergeNode merge, List replacements, CanonicalizerPhase canonicalizer) { - this.merge = merge; - this.replacements = replacements; - this.graph = merge.graph(); - this.canonicalizer = canonicalizer; - } - - /** - * Performs the actual tail duplication: - *
    - *
  • Creates a new {@link ValueAnchorNode} at the beginning of the duplicated area, an - * transfers all dependencies from the merge to this anchor.
  • - *
  • Determines the set of fixed nodes to be duplicated.
  • - *
  • Creates the new merge at the bottom of the duplicated area.
  • - *
  • Determines the complete set of duplicated nodes.
  • - *
  • Performs the actual duplication.
  • - *
- * - * @param phaseContext - */ - private void duplicate(PhaseContext phaseContext) { - Debug.log("tail duplication at merge %s in %s", merge, graph.method()); - - Mark startMark = graph.getMark(); - - DummyAnchorNode anchor = addValueAnchor(); - - // determine the fixed nodes that should be duplicated (currently: all nodes up until - // the first control - // split, end node, deopt or return. - ArrayList fixedNodes = new ArrayList<>(); - FixedNode fixed = merge.next(); - FrameState stateAfter = merge.stateAfter(); - while (fixed instanceof FixedWithNextNode) { - fixedNodes.add(fixed); - if (fixed instanceof StateSplit && ((StateSplit) fixed).stateAfter() != null) { - stateAfter = ((StateSplit) fixed).stateAfter(); - } - fixed = ((FixedWithNextNode) fixed).next(); - } - - AbstractEndNode endAfter = createNewMerge(fixed, stateAfter); - AbstractMergeNode mergeAfter = endAfter.merge(); - fixedNodes.add(endAfter); - final Set duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter); - mergeAfter.clearEnds(); - expandDuplicated(duplicatedNodes, mergeAfter); - - List endSnapshot = merge.forwardEnds().snapshot(); - List phiSnapshot = merge.phis().snapshot(); - - int endIndex = 0; - for (final EndNode forwardEnd : merge.forwardEnds()) { - Map duplicates; - if (replacements == null || replacements.get(endIndex) == null) { - duplicates = graph.addDuplicates(duplicatedNodes, graph, duplicatedNodes.size(), (DuplicationReplacement) null); - } else { - Map replace = Node.newMap(); - replace.put(replacements.get(endIndex).object(), replacements.get(endIndex)); - duplicates = graph.addDuplicates(duplicatedNodes, graph, duplicatedNodes.size(), replace); - } - for (Map.Entry phi : bottomPhis.entrySet()) { - phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey())); - } - mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter)); - - // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding - // EndNode - FixedWithNextNode anchorDuplicate = (FixedWithNextNode) duplicates.get(anchor); - // move dependencies on the ValueAnchorNode to the previous BeginNode - AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(forwardEnd); - anchorDuplicate.replaceAtUsages(InputType.Guard, prevBegin); - anchorDuplicate.replaceAtUsages(InputType.Anchor, prevBegin); - assert anchorDuplicate.hasNoUsages(); - - FixedNode next = anchorDuplicate.next(); - anchorDuplicate.setNext(null); - ((FixedWithNextNode) forwardEnd.predecessor()).setNext(next); - anchorDuplicate.safeDelete(); - - // re-wire the phi duplicates to the correct input - for (PhiNode phi : phiSnapshot) { - PhiNode phiDuplicate = (PhiNode) duplicates.get(phi); - phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd)); - phiDuplicate.safeDelete(); - } - endIndex++; - } - GraphUtil.killCFG(merge); - for (AbstractEndNode forwardEnd : endSnapshot) { - forwardEnd.safeDelete(); - } - for (PhiNode phi : phiSnapshot) { - // these phis should go away, but they still need to be anchored to a merge to be - // valid... - if (phi.isAlive()) { - phi.setMerge(mergeAfter); - } - } - canonicalizer.applyIncremental(graph, phaseContext, startMark); - Debug.dump(graph, "After tail duplication at %s", merge); - } - - /** - * Inserts a new ValueAnchorNode after the merge and transfers all dependency-usages (not - * phis) to this ValueAnchorNode. - * - * @return The new {@link ValueAnchorNode} that was created. - */ - private DummyAnchorNode addValueAnchor() { - DummyAnchorNode anchor = graph.add(new DummyAnchorNode()); - graph.addAfterFixed(merge, anchor); - merge.replaceAtUsages(InputType.Guard, anchor); - merge.replaceAtUsages(InputType.Anchor, anchor); - return anchor; - } - - /** - * Given a set of fixed nodes, this method determines the set of fixed and floating nodes - * that needs to be duplicated, i.e., all nodes that due to data flow and other dependencies - * needs to be duplicated. - * - * @param fixedNodes The set of fixed nodes that should be duplicated. - * @param stateAfter The frame state of the merge that follows the set of fixed nodes. All - * {@link ValueNode}s reachable from this state are considered to be reachable - * from within the duplicated set of nodes. - * @return The set of nodes that need to be duplicated. - */ - private Set buildDuplicatedNodeSet(final ArrayList fixedNodes, FrameState stateAfter) { - final NodeBitMap aboveBound = graph.createNodeBitMap(); - final NodeBitMap belowBound = graph.createNodeBitMap(); - - final Deque worklist = new ArrayDeque<>(); - - // Build the set of nodes that have (transitive) usages within the duplicatedNodes. - // This is achieved by iterating all nodes that are reachable via inputs from the the - // fixed nodes. - aboveBound.markAll(fixedNodes); - worklist.addAll(fixedNodes); - - // the phis at the original merge should always be duplicated - for (PhiNode phi : merge.phis()) { - aboveBound.mark(phi); - worklist.add(phi); - } - - NodeClosure aboveClosure = new NodeClosure() { - - @Override - public void apply(Node usage, Node node) { - if (node instanceof PhiNode && !fixedNodes.contains(((PhiNode) node).merge())) { - // stop iterating: phis belonging to outside merges are known to be outside. - } else if (node instanceof FixedNode) { - // stop iterating: fixed nodes within the given set are traversal roots - // anyway, and all other - // fixed nodes are known to be outside. - } else if (!aboveBound.isMarked(node)) { - worklist.add(node); - aboveBound.mark(node); - } - } - }; - - if (stateAfter != null) { - stateAfter.applyToNonVirtual(aboveClosure); - } - while (!worklist.isEmpty()) { - Node current = worklist.remove(); - for (Node input : current.inputs()) { - aboveClosure.apply(current, input); - } - } - - // Build the set of nodes that have (transitive) inputs within the duplicatedNodes. - // This is achieved by iterating all nodes that are reachable via usages from the fixed - // nodes. - belowBound.markAll(fixedNodes); - worklist.addAll(fixedNodes); - - // the phis at the original merge should always be duplicated - for (PhiNode phi : merge.phis()) { - belowBound.mark(phi); - worklist.add(phi); - } - - while (!worklist.isEmpty()) { - Node current = worklist.remove(); - for (Node usage : current.usages()) { - if (usage instanceof PhiNode && !fixedNodes.contains(((PhiNode) usage).merge())) { - // stop iterating: phis belonging to outside merges are known to be outside. - } else if (usage instanceof FixedNode) { - // stop iterating: fixed nodes within the given set are traversal roots - // anyway, and all other - // fixed nodes are known to be outside. - } else if (!belowBound.isMarked(usage)) { - worklist.add(usage); - belowBound.mark(usage); - } - } - } - - // build the intersection - belowBound.intersect(aboveBound); - Set result = Node.newSet(); - for (Node node : belowBound) { - result.add(node); - } - return result; - } - - /** - * Creates a new merge and end node construct at the end of the duplicated area. While it is - * useless in itself (merge with only one end) it simplifies the later duplication step. - * - * @param successor The successor of the duplicated set of nodes, i.e., the first node that - * should not be duplicated. - * @param stateAfterMerge The frame state that should be used for the merge. - * @return The newly created end node. - */ - private AbstractEndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) { - MergeNode newBottomMerge = graph.add(new MergeNode()); - EndNode newBottomEnd = graph.add(new EndNode()); - newBottomMerge.addForwardEnd(newBottomEnd); - newBottomMerge.setStateAfter(stateAfterMerge); - ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd); - newBottomMerge.setNext(successor); - return newBottomEnd; - } - - /** - * Expands the set of nodes to be duplicated by looking at a number of conditions: - *
    - *
  • Inputs of type {@link InputType#Value} into the duplicated set will be rerouted to a - * new phi node.
  • - *
  • Inputs of type {@link InputType#Association}, {@link InputType#Condition} and - * {@link InputType#State} into the duplicated set will be rerouted to a duplicated version - * of the inside node.
  • - *
  • Dependencies into the duplicated nodes will be replaced with dependencies on the - * merge.
  • - *
  • Inputs of type {@link InputType#Association}, {@link InputType#Condition} and - * {@link InputType#State} to outside the duplicated set will cause the outside node to be - * pulled into the duplicated set.
  • - *
- * - * @param duplicatedNodes The set of duplicated nodes that will be modified (expanded). - * @param newBottomMerge The merge that follows the duplicated set of nodes. It will be used - * for newly created phis and to as a target for dependencies that pointed into - * the duplicated set of nodes. - */ - private void expandDuplicated(Set duplicatedNodes, AbstractMergeNode newBottomMerge) { - Deque worklist = new ArrayDeque<>(duplicatedNodes); - - while (!worklist.isEmpty()) { - Node duplicated = worklist.remove(); - processUsages(duplicated, duplicatedNodes, newBottomMerge, worklist); - processInputs(duplicated, duplicatedNodes, worklist); - } - } - - private void processUsages(Node duplicated, Set duplicatedNodes, AbstractMergeNode newBottomMerge, Deque worklist) { - Set unique = Node.newSet(); - duplicated.usages().snapshotTo(unique); - Node newOutsideClone = null; - for (Node usage : unique) { - if (!duplicatedNodes.contains(usage)) { - NodePosIterator iter = usage.inputs().iterator(); - while (iter.hasNext()) { - Position pos = iter.nextPosition(); - if (pos.get(usage) == duplicated) { - switch (pos.getInputType()) { - case Extension: - case Condition: - case State: - // clone the offending node to the outside - if (newOutsideClone == null) { - newOutsideClone = duplicated.copyWithInputs(); - // this might cause other nodes to have outside usages - for (Node input : newOutsideClone.inputs()) { - if (duplicatedNodes.contains(input)) { - worklist.add(input); - } - } - } - pos.set(usage, newOutsideClone); - break; - case Guard: - case Anchor: - // re-route dependencies to the merge - pos.set(usage, newBottomMerge); - break; - case Value: - // introduce a new phi - ValueNode node = (ValueNode) duplicated; - PhiNode newPhi = bottomPhis.get(node); - if (newPhi == null) { - newPhi = graph.addWithoutUnique(new ValuePhiNode(node.stamp().unrestricted(), newBottomMerge)); - bottomPhis.put(node, newPhi); - newPhi.addInput(node); - } - pos.set(usage, newPhi); - break; - case Association: - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - } - } - } - - private void processInputs(Node duplicated, Set duplicatedNodes, Deque worklist) { - // check if this node has an input that lies outside and cannot be shared - NodePosIterator iter = duplicated.inputs().iterator(); - while (iter.hasNext()) { - Position pos = iter.nextPosition(); - Node input = pos.get(duplicated); - if (input != null && !duplicatedNodes.contains(input)) { - switch (pos.getInputType()) { - case Extension: - case Condition: - case State: - if (input != merge) { - duplicatedNodes.add(input); - worklist.add(input); - } - break; - case Association: - case Guard: - case Anchor: - case Value: - // no change needed - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - } - } -} diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java Thu Mar 19 12:47:06 2015 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.phases.common.inlining.info; -import static com.oracle.graal.compiler.common.GraalOptions.*; - import java.util.*; import com.oracle.graal.api.meta.*; @@ -39,10 +37,8 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.common.inlining.info.elem.*; -import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.util.*; /** @@ -52,8 +48,6 @@ */ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo { - private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication"); - private final List concretes; private final double[] methodProbabilities; private final double maximumMethodProbability; @@ -170,7 +164,6 @@ int numberOfMethods = concretes.size(); FixedNode continuation = invoke.next(); - ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver(); // setup merge and phi nodes for results and exceptions AbstractMergeNode returnMerge = graph.add(new MergeNode()); returnMerge.setStateAfter(invoke.stateAfter()); @@ -257,35 +250,6 @@ replacementNodes.add(null); } - if (OptTailDuplication.getValue()) { - /* - * We might want to perform tail duplication at the merge after a type switch, if there - * are invokes that would benefit from the improvement in type information. - */ - FixedNode current = returnMerge; - int opportunities = 0; - do { - if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode && - ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) { - opportunities++; - } else if (current.inputs().contains(originalReceiver)) { - opportunities++; - } - current = ((FixedWithNextNode) current).next(); - } while (current instanceof FixedWithNextNode); - - if (opportunities > 0) { - metricInliningTailDuplication.increment(); - Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities); - PhaseContext phaseContext = new PhaseContext(providers); - CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); - if (ImmutableCode.getValue()) { - canonicalizer.disableReadCanonicalization(); - } - TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer); - } - } - Collection canonicalizeNodes = new ArrayList<>(); // do the actual inlining for every invoke for (int i = 0; i < numberOfMethods; i++) { diff -r e018185695f6 -r 812fc403db8c 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 Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Thu Mar 19 12:47:06 2015 +0100 @@ -150,8 +150,9 @@ } else { Block currentBlock = b; assert currentBlock != null; + Block latestBlock = calcLatestBlock(b, isOutOfLoops, currentNode, currentNodeMap); - assert AbstractControlFlowGraph.dominates(currentBlock, latestBlock) || currentNode instanceof VirtualState : currentNode + " " + currentBlock + " " + latestBlock; + assert checkLatestEarliestRelation(currentNode, currentBlock, latestBlock); if (latestBlock != currentBlock) { if (currentNode instanceof FloatingReadNode) { @@ -200,6 +201,12 @@ return watchListMap; } + private static boolean checkLatestEarliestRelation(Node currentNode, Block earliestBlock, Block latestBlock) { + assert AbstractControlFlowGraph.dominates(earliestBlock, latestBlock) || (currentNode instanceof VirtualState && latestBlock == earliestBlock.getDominator()) : String.format("%s %s %s", + currentNode, earliestBlock, latestBlock); + return true; + } + private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap> blockToNodesMap, NodeMap nodeMap) { for (Block b : cfg.getBlocks()) { List nodes = blockToNodesMap.get(b); @@ -414,9 +421,11 @@ assert currentNode.hasUsages(); for (Node usage : currentNode.usages()) { block = calcBlockForUsage(currentNode, usage, block, currentNodeMap); + assert checkLatestEarliestRelation(currentNode, earliestBlock, block); if (scheduleOutOfLoops) { - while (block.getLoopDepth() > earliestBlock.getLoopDepth()) { + while (block.getLoopDepth() > earliestBlock.getLoopDepth() && block != earliestBlock.getDominator()) { block = block.getDominator(); + assert checkLatestEarliestRelation(currentNode, earliestBlock, block); } } if (block == earliestBlock) { diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Thu Mar 19 12:47:06 2015 +0100 @@ -151,25 +151,25 @@ Registration r = new Registration(plugins, declaringClass); r.register1("reverseBytes", type, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(kind, b.append(new ReverseBytesNode(value).canonical(null, value))); + b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null, value))); return true; } }); r.register1("bitCount", type, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Int, b.append(new BitCountNode(value).canonical(null, value))); + b.push(Kind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null, value))); return true; } }); r.register2("divideUnsigned", type, type, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) { - b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); + b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); return true; } }); r.register2("remainderUnsigned", type, type, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) { - b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); + b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); return true; } }); @@ -183,7 +183,7 @@ ReverseBytesNode reverse = b.append(new ReverseBytesNode(value)); RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16)))); ZeroExtendNode charCast = b.append(new ZeroExtendNode(b.append(new NarrowNode(rightShift, 16)), 32)); - b.push(Kind.Char.getStackKind(), b.append(charCast.canonical(null, value))); + b.push(Kind.Char.getStackKind(), b.recursiveAppend(charCast.canonical(null, value))); return true; } }); @@ -197,7 +197,7 @@ ReverseBytesNode reverse = b.append(new ReverseBytesNode(value)); RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16)))); SignExtendNode charCast = b.append(new SignExtendNode(b.append(new NarrowNode(rightShift, 16)), 32)); - b.push(Kind.Short.getStackKind(), b.append(charCast.canonical(null, value))); + b.push(Kind.Short.getStackKind(), b.recursiveAppend(charCast.canonical(null, value))); return true; } }); @@ -207,13 +207,13 @@ Registration r = new Registration(plugins, Float.class); r.register1("floatToRawIntBits", float.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Int, b.append(new ReinterpretNode(Kind.Int, value).canonical(null, value))); + b.push(Kind.Int, b.recursiveAppend(new ReinterpretNode(Kind.Int, value).canonical(null, value))); return true; } }); r.register1("intBitsToFloat", int.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Float, b.append(new ReinterpretNode(Kind.Float, value).canonical(null, value))); + b.push(Kind.Float, b.recursiveAppend(new ReinterpretNode(Kind.Float, value).canonical(null, value))); return true; } }); @@ -223,13 +223,13 @@ Registration r = new Registration(plugins, Double.class); r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Long, b.append(new ReinterpretNode(Kind.Long, value).canonical(null, value))); + b.push(Kind.Long, b.recursiveAppend(new ReinterpretNode(Kind.Long, value).canonical(null, value))); return true; } }); r.register1("longBitsToDouble", long.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(new ReinterpretNode(Kind.Double, value).canonical(null, value))); + b.push(Kind.Double, b.recursiveAppend(new ReinterpretNode(Kind.Double, value).canonical(null, value))); return true; } }); @@ -239,32 +239,32 @@ Registration r = new Registration(plugins, Math.class); r.register1("abs", Float.TYPE, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Float, b.append(new AbsNode(value).canonical(null, value))); + b.push(Kind.Float, b.recursiveAppend(new AbsNode(value).canonical(null, value))); return true; } }); r.register1("abs", Double.TYPE, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(new AbsNode(value).canonical(null, value))); + b.push(Kind.Double, b.recursiveAppend(new AbsNode(value).canonical(null, value))); return true; } }); r.register1("sqrt", Double.TYPE, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(new SqrtNode(value).canonical(null, value))); + b.push(Kind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null, value))); return true; } }); if (getAndSetEnabled(arch)) { r.register1("log", Double.TYPE, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG))); + b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG))); return true; } }); r.register1("log10", Double.TYPE, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG10))); + b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG10))); return true; } }); @@ -313,25 +313,25 @@ r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE)); r.register2("divide", int.class, int.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Int, b.append(new UnsignedDivNode(x, y).canonical(null, x, y))); + b.push(Kind.Int, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); return true; } }); r.register2("divide", long.class, long.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Long, b.append(new UnsignedDivNode(x, y).canonical(null, x, y))); + b.push(Kind.Long, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); return true; } }); r.register2("remainder", int.class, int.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Int, b.append(new UnsignedRemNode(x, y).canonical(null, x, y))); + b.push(Kind.Int, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); return true; } }); r.register2("remainder", long.class, long.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Long, b.append(new UnsignedRemNode(x, y).canonical(null, x, y))); + b.push(Kind.Long, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); return true; } }); @@ -366,14 +366,14 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) { ValueNode nullCheckedType = nullCheckedValue(b, type); LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), nullCheckedType, object)); - b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null))); + b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null))); return true; } }); r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode otherType) { - ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType)); - b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null))); + ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType)); + b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null))); return true; } }); diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Thu Mar 19 12:47:06 2015 +0100 @@ -53,13 +53,9 @@ @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess; - public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length) { + public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter Kind kind) { super(TYPE, StampFactory.forKind(Kind.Boolean)); - // Ignore nullness in stamp equality test - assert array1.stamp().join(StampFactory.objectNonNull()).equals(array2.stamp().join(StampFactory.objectNonNull())); - ObjectStamp array1Stamp = (ObjectStamp) array1.stamp(); - ResolvedJavaType componentType = array1Stamp.type().getComponentType(); - this.kind = componentType.getKind(); + this.kind = kind; this.array1 = array1; this.array2 = array2; this.length = length; @@ -109,28 +105,39 @@ } @NodeIntrinsic - public static native boolean equals(boolean[] array1, boolean[] array2, int length); + public static native boolean equals(Object array1, Object array2, int length, @ConstantNodeParameter Kind kind); - @NodeIntrinsic - public static native boolean equals(byte[] array1, byte[] array2, int length); + public static boolean equals(boolean[] array1, boolean[] array2, int length) { + return equals(array1, array2, length, Kind.Boolean); + } - @NodeIntrinsic - public static native boolean equals(char[] array1, char[] array2, int length); + public static boolean equals(byte[] array1, byte[] array2, int length) { + return equals(array1, array2, length, Kind.Byte); + } - @NodeIntrinsic - public static native boolean equals(short[] array1, short[] array2, int length); + public static boolean equals(char[] array1, char[] array2, int length) { + return equals(array1, array2, length, Kind.Char); + } - @NodeIntrinsic - public static native boolean equals(int[] array1, int[] array2, int length); + public static boolean equals(short[] array1, short[] array2, int length) { + return equals(array1, array2, length, Kind.Short); + } - @NodeIntrinsic - public static native boolean equals(long[] array1, long[] array2, int length); + public static boolean equals(int[] array1, int[] array2, int length) { + return equals(array1, array2, length, Kind.Int); + } - @NodeIntrinsic - public static native boolean equals(float[] array1, float[] array2, int length); + public static boolean equals(long[] array1, long[] array2, int length) { + return equals(array1, array2, length, Kind.Long); + } - @NodeIntrinsic - public static native boolean equals(double[] array1, double[] array2, int length); + public static boolean equals(float[] array1, float[] array2, int length) { + return equals(array1, array2, length, Kind.Float); + } + + public static boolean equals(double[] array1, double[] array2, int length) { + return equals(array1, array2, length, Kind.Double); + } @Override public void generate(NodeLIRBuilderTool gen) { diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARCScratchRegister.java --- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARCScratchRegister.java Thu Mar 19 12:46:38 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.sparc; - -import com.oracle.graal.api.code.*; - -public final class SPARCScratchRegister implements AutoCloseable { - private final ThreadLocal locked = new ThreadLocal<>(); - private final ThreadLocal where = new ThreadLocal<>(); - private final Register register; - private static final SPARCScratchRegister scratch1 = new SPARCScratchRegister(SPARC.g3); - private static final SPARCScratchRegister scratch2 = new SPARCScratchRegister(SPARC.g1); - private static final boolean LOG_REQUEST_STACK = false; - - private SPARCScratchRegister(Register register) { - super(); - this.register = register; - } - - public Register getRegister() { - if (locked.get() == null) { - locked.set(false); - } - boolean isLocked = locked.get(); - if (isLocked) { - if (LOG_REQUEST_STACK) { - where.get().printStackTrace(); - } - throw new RuntimeException("Temp Register is already taken!"); - } else { - if (LOG_REQUEST_STACK) { - where.set(new Exception()); - } - locked.set(true); - return register; - } - } - - public void close() { - boolean isLocked = locked.get(); - if (isLocked) { - locked.set(false); - } else { - throw new RuntimeException("Temp Register is not taken!"); - } - } - - public static SPARCScratchRegister get() { - if (scratch1.isLocked()) { - return scratch2; - } else { - return scratch1; - } - } - - public boolean isLocked() { - Boolean isLocked = locked.get(); - if (isLocked == null) { - return false; - } else { - return isLocked; - } - } -} diff -r e018185695f6 -r 812fc403db8c graal/com.oracle.graal.truffle.hotspot.sparc/src/com/oracle/graal/truffle/hotspot/sparc/SPARCOptimizedCallTargetInstumentationFactory.java --- a/graal/com.oracle.graal.truffle.hotspot.sparc/src/com/oracle/graal/truffle/hotspot/sparc/SPARCOptimizedCallTargetInstumentationFactory.java Thu Mar 19 12:46:38 2015 +0100 +++ b/graal/com.oracle.graal.truffle.hotspot.sparc/src/com/oracle/graal/truffle/hotspot/sparc/SPARCOptimizedCallTargetInstumentationFactory.java Thu Mar 19 12:47:06 2015 +0100 @@ -35,11 +35,11 @@ import com.oracle.graal.api.runtime.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.framemap.*; -import com.oracle.graal.sparc.*; import com.oracle.graal.truffle.*; import com.oracle.graal.truffle.hotspot.*; @@ -53,7 +53,7 @@ protected void injectTailCallCode(HotSpotVMConfig config, HotSpotRegistersProvider registers) { @SuppressWarnings("hiding") SPARCMacroAssembler asm = (SPARCMacroAssembler) this.asm; - try (SPARCScratchRegister scratch = SPARCScratchRegister.get()) { + try (ScratchRegister scratch = asm.getScratchRegister()) { Register thisRegister = codeCache.getRegisterConfig().getCallingConventionRegisters(JavaCall, Object)[0]; Register spillRegister = scratch.getRegister(); Label doProlog = new Label(); diff -r e018185695f6 -r 812fc403db8c src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java --- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java Thu Mar 19 12:47:06 2015 +0100 @@ -45,6 +45,7 @@ System.out.println(" -e: sort events by elapsed time"); System.out.println(" -n: sort events by name and start"); System.out.println(" -L: print eliminated locks"); + System.out.println(" -Q: print compile queue activity"); System.exit(exitcode); } @@ -54,6 +55,7 @@ boolean printInlining = false; boolean cleanup = false; boolean printEliminatedLocks = false; + boolean printCompileQueue = false; int index = 0; while (args.length > index) { @@ -80,6 +82,9 @@ } else if (args[index].equals("-L")) { printEliminatedLocks = true; index++; + } else if (args[index].equals("-Q")) { + printCompileQueue = true; + index++; } else { break; } @@ -92,32 +97,17 @@ while (index < args.length) { ArrayList events = LogParser.parse(args[index], cleanup); - if (printEliminatedLocks) { - Collections.sort(events, defaultSort); - for (LogEvent e : events) { - if (e instanceof Compilation) { - Compilation c = (Compilation) e; - List eliminated = c.getEliminatedLocks(); - if (!eliminated.isEmpty()) { - c.print(System.out); - System.out.println(" Eliminated locks"); - for (JVMState jvms : eliminated) { - System.err.print(" "); - while (jvms != null) { - System.out.printf(" %s.%s@%d", jvms.method.getHolder().replace('/', '.'), jvms.method.getName(), jvms.bci); - jvms = jvms.outer; - } - System.out.println(); - } - } - } - } + if (printCompileQueue) { + printCompileQueue(events, System.out); + } else if (printEliminatedLocks) { + printEliminatedLocks(events, System.out, defaultSort); } else if (statistics) { printStatistics(events, System.out); } else { Collections.sort(events, defaultSort); for (LogEvent c : events) { if (c instanceof NMethod) continue; + if (c instanceof TaskEvent) continue; System.out.printf("%f ", c.getStart()); if (printInlining && c instanceof Compilation) { @@ -131,7 +121,81 @@ index++; } } + + public static void printCompileQueue(ArrayList events, PrintStream out) { + int[] levels = new int[5]; + HashMap tasks = new HashMap(); + + out.printf("%7s ", "Stamp"); + for (int i = 1; i <= 4; i++) { + out.printf(" Level%d", i); + } + out.printf(" %10s", "Kind"); + out.println(); + for (LogEvent e : events) { + if (e instanceof TaskEvent) { + boolean demoted = false; + TaskEvent t = (TaskEvent) e; + TaskEvent start = tasks.get(t.getId()); + switch (t.getKind()) { + case Enqueue: + assert start == null; + levels[t.getLevel()] = levels[t.getLevel()] + 1; + tasks.put(t.getId(), t); + break; + + case Finish: + case Dequeue: + if (start != null && start.getLevel() != t.getLevel()) { + // Sometimes tasks are moved to a lower + // compilation level when the queue fills. + demoted = true; + levels[start.getLevel()] = levels[start.getLevel()] - 1; + } else { + levels[t.getLevel()] = levels[t.getLevel()] - 1; + } + break; + default: + throw new InternalError(); + } + out.printf("%7.3f ", t.getStart()); + for (int i = 1; i <= 4; i++) { + out.printf(" %6d", levels[i]); + } + out.printf(" %10s", t.getKind()); + if (t.getComment() != null) { + out.printf(" %s", t.getComment()); + } + if (demoted) { + out.printf(" %d->%d", start.getLevel(), t.getLevel()); + } + out.println(); + } + } + } + public static void printEliminatedLocks(ArrayList events, PrintStream out, Comparator defaultSort) { + Collections.sort(events, defaultSort); + for (LogEvent e : events) { + if (e instanceof Compilation) { + Compilation c = (Compilation) e; + List eliminated = c.getEliminatedLocks(); + if (!eliminated.isEmpty()) { + c.print(out); + out.println(" Eliminated locks"); + for (JVMState jvms : eliminated) { + System.err.print(" "); + while (jvms != null) { + out.printf(" %s.%s@%d", jvms.method.getHolder().replace('/', '.'), jvms.method.getName(), jvms.bci); + jvms = jvms.outer; + } + out.println(); + } + } + } + } + } + public static void printStatistics(ArrayList events, PrintStream out) { long cacheSize = 0; long maxCacheSize = 0; diff -r e018185695f6 -r 812fc403db8c src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java --- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Thu Mar 19 12:47:06 2015 +0100 @@ -204,7 +204,7 @@ } } else { if (c == null) { - throw new InternalError("can't find compilation " + ble.getId() + " for " + ble); + // throw new InternalError("can't find compilation " + ble.getId() + " for " + ble); } } } @@ -363,6 +363,17 @@ scopes.peek().last().setReason(search(atts, "reason")); } else if (qname.equals("failure")) { failureReason = search(atts, "reason"); + } else if (qname.equals("task_queued")) { + String id = makeId(atts); + int level = Integer.parseInt(search(atts, "level")); + TaskEvent t = new TaskEvent(Double.parseDouble(search(atts, "stamp")), id, level, TaskEvent.Kind.Enqueue); + events.add(t); + } else if (qname.equals("task_dequeued")) { + String id = makeId(atts); + int level = Integer.parseInt(search(atts, "level")); + TaskEvent t = new TaskEvent(Double.parseDouble(search(atts, "stamp")), id, level, TaskEvent.Kind.Dequeue); + t.setComment(search(atts, "comment")); + events.add(t); } else if (qname.equals("task_done")) { compile.setEnd(Double.parseDouble(search(atts, "stamp"))); if (Integer.parseInt(search(atts, "success")) == 0) { @@ -425,6 +436,12 @@ parseLong(atts.getValue("size"))); nmethods.put(id, nm); events.add(nm); + + int level = Integer.parseInt(search(atts, "level")); + if (level > 0) { + TaskEvent t = new TaskEvent(Double.parseDouble(search(atts, "stamp")), id, level, TaskEvent.Kind.Finish); + events.add(t); + } } else if (qname.equals("parse")) { Method m = method(search(atts, "method")); if (scopes.size() == 0) { diff -r e018185695f6 -r 812fc403db8c src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/TaskEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/TaskEvent.java Thu Mar 19 12:47:06 2015 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 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.sun.hotspot.tools.compiler; + +import java.io.PrintStream; + +public class TaskEvent extends BasicLogEvent { + private int level; + private String comment; + private Kind kind; + + enum Kind { + Enqueue, + Dequeue, + Finish + } + + public TaskEvent(double start, String id, int level, Kind kind) { + super(start, id); + this.level = level; + this.kind = kind; + } + + void setComment(String comment) { + this.comment = comment; + } + + String getComment() { + return comment; + } + + int getLevel() { + return level; + } + + Kind getKind() { + return kind; + } + + public void print(PrintStream stream) { + stream.printf("%s id='%s' level='%s' %s%n", start, id, level, kind); + } +} diff -r e018185695f6 -r 812fc403db8c src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Thu Mar 19 12:47:06 2015 +0100 @@ -558,6 +558,24 @@ // ------------------------------------------------------------------ +// CompileTask::log_task_dequeued +void CompileTask::log_task_dequeued(const char* comment) { + if (LogCompilation && xtty != NULL) { + Thread* thread = Thread::current(); + ttyLocker ttyl; + ResourceMark rm(thread); + + xtty->begin_elem("task_dequeued"); + log_task(xtty); + if (comment != NULL) { + xtty->print(" comment='%s'", comment); + } + xtty->end_elem(); + } +} + + +// ------------------------------------------------------------------ // CompileTask::log_task_start void CompileTask::log_task_start(CompileLog* log) { log->begin_head("task"); @@ -1202,10 +1220,12 @@ blocking = false; } - // Don't allow blocking compiles if inside a class initializer + // Don't allow blocking compiles if inside a class initializer or while performing class loading vframeStream vfst((JavaThread*) thread); for (; !vfst.at_end(); vfst.next()) { - if (vfst.method()->is_static_initializer()) { + if (vfst.method()->is_static_initializer() || + (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && + vfst.method()->name() == vmSymbols::loadClass_name())) { blocking = false; break; } diff -r e018185695f6 -r 812fc403db8c src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/vm/compiler/compileBroker.hpp Thu Mar 19 12:47:06 2015 +0100 @@ -129,6 +129,7 @@ void log_task(xmlStream* log); void log_task_queued(); + void log_task_dequeued(const char* comment); void log_task_start(CompileLog* log); void log_task_done(CompileLog* log); }; diff -r e018185695f6 -r 812fc403db8c src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/vm/graal/graalCompiler.cpp Thu Mar 19 12:47:06 2015 +0100 @@ -65,6 +65,9 @@ void GraalCompiler::bootstrap() { JavaThread* THREAD = JavaThread::current(); _bootstrapping = true; + // Allow bootstrap to perform Graal compilations of itself + bool c1only = GraalCompileWithC1Only; + GraalCompileWithC1Only = false; ResourceMark rm; HandleMark hm; if (PrintBootstrap) { @@ -105,6 +108,7 @@ if (PrintBootstrap) { tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled); } + GraalCompileWithC1Only = c1only; _bootstrapping = false; } diff -r e018185695f6 -r 812fc403db8c src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/vm/graal/graalGlobals.hpp Thu Mar 19 12:47:06 2015 +0100 @@ -82,6 +82,12 @@ product(bool, GraalHProfEnabled, false, \ "Is Heap Profiler enabled") \ \ + product(bool, GraalCompileWithC1Only, true, \ + "Only compile Graal classes with C1") \ + \ + product(bool, GraalCompileAppFirst, false, \ + "Prioritize application compilations over Graal compilations") \ + \ develop(bool, GraalUseFastLocking, true, \ "Use fast inlined locking code") \ \ diff -r e018185695f6 -r 812fc403db8c src/share/vm/runtime/advancedThresholdPolicy.cpp --- a/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Mar 19 12:47:06 2015 +0100 @@ -157,6 +157,9 @@ // Called with the queue locked and with at least one element CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) { +#ifdef COMPILERGRAAL + CompileTask *max_non_graal_task = NULL; +#endif CompileTask *max_task = NULL; Method* max_method = NULL; jlong t = os::javaTimeMillis(); @@ -175,6 +178,7 @@ if (PrintTieredEvents) { print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level()); } + task->log_task_dequeued("stale"); CompileTaskWrapper ctw(task); // Frees the task compile_queue->remove(task); method->clear_queued_for_compilation(); @@ -188,9 +192,30 @@ max_method = method; } } +#ifdef COMPILERGRAAL + if (GraalCompileAppFirst && (task->comp_level() == CompLevel_full_optimization || !method->has_compiled_code()) && + SystemDictionary::graal_loader() != NULL && + method->method_holder()->class_loader() != SystemDictionary::graal_loader()) { + if (max_non_graal_task == NULL) { + max_non_graal_task = task; + } else { + // Select a method with a higher rate + if (compare_methods(method, max_non_graal_task->method())) { + max_non_graal_task = task; + } + } + } +#endif task = next_task; } +#ifdef COMPILERGRAAL + if (max_non_graal_task != NULL) { + max_task = max_non_graal_task; + max_method = max_task->method(); + } +#endif + if (max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile && is_method_profiled(max_method)) { max_task->set_comp_level(CompLevel_limited_profile); diff -r e018185695f6 -r 812fc403db8c src/share/vm/runtime/simpleThresholdPolicy.inline.hpp --- a/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Thu Mar 19 12:46:38 2015 +0100 +++ b/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Thu Mar 19 12:47:06 2015 +0100 @@ -55,6 +55,13 @@ // Determine if a given method is such a case. bool SimpleThresholdPolicy::is_trivial(Method* method) { if (method->is_accessor()) return true; +#ifdef COMPILERGRAAL + if (TieredCompilation && GraalCompileWithC1Only && + SystemDictionary::graal_loader() != NULL && + method->method_holder()->class_loader() == SystemDictionary::graal_loader()) { + return true; + } +#endif if (method->code() != NULL) { MethodData* mdo = method->method_data(); if (mdo != NULL && mdo->num_loops() == 0 &&