# HG changeset patch # User Thomas Wuerthinger # Date 1423104162 -3600 # Node ID 183f7d3a93e55a113ff8bc297f7cc4cec42813bc # Parent 276bc2752feb7cf216f45a69bf8b46d80b76a85f# Parent b8b8f0fcb8c371581c74917e3b269ab005fb0e9e Merge. diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Thu Feb 05 03:42:42 2015 +0100 @@ -95,7 +95,7 @@ BciBlockMapping blockMap; try (Scope ds = Debug.scope("BciBlockMapping")) { // compute the block map, setup exception handlers and get the entrypoint(s) - blockMap = BciBlockMapping.create(method, graphBuilderConfig.doLivenessAnalysis()); + blockMap = BciBlockMapping.create(method, graphBuilderConfig.doLivenessAnalysis(), false); } catch (Throwable e) { throw Debug.handle(e); } diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 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 Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Thu Feb 05 03:42:42 2015 +0100 @@ -737,7 +737,10 @@ private void genGetStatic(JavaField field) { Kind kind = field.getKind(); if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field)); + GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin(); + if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) { + appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field)); + } } else { handleUnresolvedLoadField(field, null); } diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Thu Feb 05 03:42:42 2015 +0100 @@ -81,6 +81,7 @@ public int endBci; public boolean isExceptionEntry; public boolean isLoopHeader; + public boolean isLastLoopEnd; public int loopId; /** @@ -358,14 +359,16 @@ private final boolean doLivenessAnalysis; public LocalLiveness liveness; private int blocksNotYetAssignedId; + private final boolean consecutiveLoopBlocks; /** * Creates a new BlockMap instance from bytecode of the given method . * * @param method the compiler interface method containing the code */ - private BciBlockMapping(ResolvedJavaMethod method, boolean doLivenessAnalysis) { + private BciBlockMapping(ResolvedJavaMethod method, boolean doLivenessAnalysis, boolean consecutiveLoopBlocks) { this.doLivenessAnalysis = doLivenessAnalysis; + this.consecutiveLoopBlocks = consecutiveLoopBlocks; this.method = method; this.exceptionHandlers = method.getExceptionHandlers(); this.stream = new BytecodeStream(method.getCode()); @@ -737,6 +740,7 @@ } private void computeBlockOrder() { + int maxBlocks = blocksNotYetAssignedId; this.blocks = new BciBlock[blocksNotYetAssignedId]; long loop = computeBlockOrder(blockMap[0]); @@ -747,23 +751,61 @@ throw new BailoutException("Non-reducible loop"); } - if (blocks[0] == null) { - purgeLeadingNullBlocks(); + if (blocks[0] != null && this.nextLoop == 0) { + // No unreached blocks and no loops + for (int i = 0; i < blocks.length; ++i) { + blocks[i].setId(i); + } + return; + } + + // Purge null entries for unreached blocks and sort blocks such that loop bodies are always + // consecutively in the array. + int blockCount = maxBlocks - blocksNotYetAssignedId; + BciBlock[] newBlocks = new BciBlock[blockCount]; + int next = 0; + for (int i = 0; i < blocks.length; ++i) { + BciBlock b = blocks[i]; + if (b != null) { + b.setId(next); + newBlocks[next++] = b; + if (consecutiveLoopBlocks && b.isLoopHeader) { + next = handleLoopHeader(newBlocks, next, i, b); + } + } + } + blocks = newBlocks; + + if (consecutiveLoopBlocks && this.nextLoop > 2) { + System.out.println(); + for (int i = 0; i < blocks.length; ++i) { + String succ = ""; + for (BciBlock succBlock : blocks[i].getSuccessors()) { + succ += succBlock.getId() + " "; + } + System.out.printf("%3s %10s %s %s succ=[%s]\n", blocks[i].getId(), Long.toBinaryString(blocks[i].loops), blocks[i].isLoopHeader, blocks[i].isLastLoopEnd, succ); + } + System.out.println(); } } - private void purgeLeadingNullBlocks() { - // Purge leading null values due to unreachable blocks. - int i = 0; - for (; i < blocks.length; ++i) { - if (blocks[i] != null) { - break; + private int handleLoopHeader(BciBlock[] newBlocks, int nextStart, int i, BciBlock loopHeader) { + int next = nextStart; + BciBlock last = loopHeader; + for (int j = i + 1; j < blocks.length; ++j) { + BciBlock other = blocks[j]; + if (other != null && (other.loops & (1L << loopHeader.loopId)) != 0) { + other.setId(next); + newBlocks[next++] = other; + last = other; + blocks[j] = null; + if (other.isLoopHeader) { + next = handleLoopHeader(newBlocks, next, j, other); + } } } - blocks = Arrays.copyOfRange(blocks, i, blocks.length); - for (i = 0; i < blocks.length; ++i) { - blocks[i].setId(i); - } + last.isLastLoopEnd = true; + return next; } public void log(String name) { @@ -885,6 +927,7 @@ if (successor.active) { // Reached block via backward branch. block.isLoopEnd = true; + loops |= (1L << successor.loopId); } } @@ -898,7 +941,6 @@ block.active = false; blocksNotYetAssignedId--; blocks[blocksNotYetAssignedId] = block; - block.setId(blocksNotYetAssignedId); return loops; } @@ -1154,8 +1196,8 @@ } } - public static BciBlockMapping create(ResolvedJavaMethod method, boolean doLivenessAnalysis) { - BciBlockMapping map = new BciBlockMapping(method, doLivenessAnalysis); + public static BciBlockMapping create(ResolvedJavaMethod method, boolean doLivenessAnalysis, boolean consecutiveLoopBlocks) { + BciBlockMapping map = new BciBlockMapping(method, doLivenessAnalysis, consecutiveLoopBlocks); map.build(); if (Debug.isDumpEnabled()) { Debug.dump(map, method.format("After block building %f %R %H.%n(%P)")); diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Thu Feb 05 03:42:42 2015 +0100 @@ -39,6 +39,7 @@ private GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin; private GraphBuilderPlugins.ParameterPlugin parameterPlugin; private GraphBuilderPlugins.InlineInvokePlugin inlineInvokePlugin; + private GraphBuilderPlugins.LoopExplosionPlugin loopExplosionPlugin; public static enum DebugInfoMode { SafePointsOnly, @@ -167,4 +168,12 @@ public void setInlineInvokePlugin(GraphBuilderPlugins.InlineInvokePlugin inlineInvokePlugin) { this.inlineInvokePlugin = inlineInvokePlugin; } + + public GraphBuilderPlugins.LoopExplosionPlugin getLoopExplosionPlugin() { + return loopExplosionPlugin; + } + + public void setLoopExplosionPlugin(GraphBuilderPlugins.LoopExplosionPlugin loopExplosionPlugin) { + this.loopExplosionPlugin = loopExplosionPlugin; + } } diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 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 Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Feb 05 03:42:42 2015 +0100 @@ -191,6 +191,7 @@ private FixedWithNextNode beforeUnwindNode; private FixedWithNextNode lastInstr; // the last instruction added + private final boolean explodeLoops; public BytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI) { super(metaAccess, method, graphBuilderConfig, optimisticOpts); @@ -200,6 +201,13 @@ lnt = method.getLineNumberTable(); previousLineNumber = -1; } + + LoopExplosionPlugin loopExplosionPlugin = graphBuilderConfig.getLoopExplosionPlugin(); + if (loopExplosionPlugin != null) { + explodeLoops = loopExplosionPlugin.shouldExplodeLoops(method); + } else { + explodeLoops = false; + } } public ValueNode getReturnValue() { @@ -228,7 +236,7 @@ try (Indent indent = Debug.logAndIndent("build graph for %s", method)) { // compute the block map, setup exception handlers and get the entrypoint(s) - BciBlockMapping blockMap = BciBlockMapping.create(method, graphBuilderConfig.doLivenessAnalysis()); + BciBlockMapping blockMap = BciBlockMapping.create(method, graphBuilderConfig.doLivenessAnalysis(), explodeLoops); loopHeaders = blockMap.getLoopHeaders(); liveness = blockMap.liveness; @@ -571,7 +579,7 @@ @Override protected ValueNode genIntegerEquals(ValueNode x, ValueNode y) { - return new IntegerEqualsNode(x, y); + return IntegerEqualsNode.create(x, y, constantReflectionProvider); } @Override @@ -941,7 +949,7 @@ JsrScope scope = currentBlock.getJsrScope(); int retAddress = scope.nextReturnAddress(); ConstantNode returnBciNode = getJsrConstant(retAddress); - LogicNode guard = new IntegerEqualsNode(local, returnBciNode); + LogicNode guard = IntegerEqualsNode.create(local, returnBciNode, constantReflectionProvider); guard = currentGraph.unique(guard); append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile)); if (!successor.getJsrScope().equals(scope.pop())) { diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Thu Feb 05 03:42:42 2015 +0100 @@ -38,7 +38,15 @@ public interface GraphBuilderPlugins { public interface LoadFieldPlugin extends GraphBuilderPlugin { - boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field); + @SuppressWarnings("unused") + default boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) { + return false; + } + + @SuppressWarnings("unused") + default boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) { + return false; + } } public interface ParameterPlugin extends GraphBuilderPlugin { @@ -49,6 +57,10 @@ boolean shouldInlineInvoke(ResolvedJavaMethod method, int depth); } + public interface LoopExplosionPlugin extends GraphBuilderPlugin { + boolean shouldExplodeLoops(ResolvedJavaMethod method); + } + /** * Plugin for handling a method invocation. */ diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Thu Feb 05 03:42:42 2015 +0100 @@ -32,7 +32,7 @@ import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "==") -public class IntegerEqualsNode extends CompareNode { +public final class IntegerEqualsNode extends CompareNode { public IntegerEqualsNode(ValueNode x, ValueNode y) { super(Condition.EQ, false, x, y); @@ -40,6 +40,15 @@ assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object; } + public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { + LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false); + if (result != null) { + return result; + } else { + return new IntegerEqualsNode(x, y); + } + } + @Override protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { PrimitiveConstant primitive = (PrimitiveConstant) constant; diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Thu Feb 05 03:42:42 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "==") -public class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable { +public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable { public ObjectEqualsNode(ValueNode x, ValueNode y) { super(x, y); diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Thu Feb 05 03:42:42 2015 +0100 @@ -49,7 +49,10 @@ this.arguments = arguments; int size = descriptor.getSize(); this.locals = new Object[size]; - Arrays.fill(locals, descriptor.getDefaultValue()); + Object defaultValue = descriptor.getDefaultValue(); + if (defaultValue != null) { + Arrays.fill(locals, defaultValue); + } this.primitiveLocals = new long[size]; this.tags = new byte[size]; } diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Thu Feb 05 03:42:42 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,19 +146,26 @@ private class InterceptLoadFieldPlugin implements GraphBuilderPlugins.LoadFieldPlugin { public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) { - System.out.println("Load field plugin called for receiver: " + receiver + " and field " + field); - if (receiver.isConstant()) { JavaConstant asJavaConstant = receiver.asJavaConstant(); JavaConstant result = providers.getConstantReflection().readConstantFieldValue(field, asJavaConstant); if (result != null) { ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, providers.getMetaAccess())); - builder.push(constantNode.getKind(), constantNode); + builder.push(constantNode.getKind().getStackKind(), constantNode); return true; } } return false; } + + public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) { + if (TruffleCompilerOptions.TruffleExcludeAssertions.getValue() && staticField.getName().equals("$assertionsDisabled")) { + ConstantNode trueNode = builder.append(ConstantNode.forBoolean(true)); + builder.push(trueNode.getKind().getStackKind(), trueNode); + return true; + } + return false; + } } private class InterceptReceiverPlugin implements GraphBuilderPlugins.ParameterPlugin { @@ -185,12 +192,21 @@ } + private class LoopExplosionPlugin implements GraphBuilderPlugins.LoopExplosionPlugin { + + public boolean shouldExplodeLoops(ResolvedJavaMethod method) { + return method.getAnnotation(ExplodeLoop.class) != null; + } + + } + @SuppressWarnings("unused") private void fastPartialEvaluation(OptimizedCallTarget callTarget, Assumptions assumptions, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) { GraphBuilderConfiguration newConfig = configForRoot.copy(); newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin()); newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget)); newConfig.setInlineInvokePlugin(new InlineInvokePlugin()); + newConfig.setLoopExplosionPlugin(new LoopExplosionPlugin()); DefaultGraphBuilderPlugins plugins = new DefaultGraphBuilderPlugins(); Iterable sl = Services.load(GraphBuilderPluginsProvider.class); for (GraphBuilderPluginsProvider p : sl) { @@ -199,6 +215,14 @@ new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), newConfig, plugins, TruffleCompilerImpl.Optimizations).apply(graph); Debug.dump(graph, "After FastPE"); + + // Do single partial escape and canonicalization pass. + try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) { + new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext); + new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext); + } catch (Throwable t) { + Debug.handle(t); + } } private void partialEvaluation(final OptimizedCallTarget callTarget, final Assumptions assumptions, final StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) { diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu Feb 05 03:42:42 2015 +0100 @@ -44,6 +44,9 @@ @Option(help = "Restrict compilation to comma-separated list of includes (or excludes prefixed with tilde)", type = OptionType.Debug) public static final OptionValue TruffleCompileOnly = new OptionValue<>(null); + @Option(help = "Exclude assertion code from Truffle compilations", type = OptionType.Debug) + public static final StableOptionValue TruffleExcludeAssertions = new StableOptionValue<>(true); + @Option(help = "Compile call target when call count exceeds this threshold", type = OptionType.User) public static final OptionValue TruffleCompilationThreshold = new OptionValue<>(1000); diff -r b8b8f0fcb8c3 -r 183f7d3a93e5 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java Wed Feb 04 17:02:31 2015 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java Thu Feb 05 03:42:42 2015 +0100 @@ -27,13 +27,16 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.java.*; import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin; import com.oracle.graal.java.GraphBuilderPlugins.Registration; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.truffle.*; import com.oracle.graal.truffle.nodes.frame.*; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; /** * Provider of {@link GraphBuilderPlugin}s for Truffle classes. @@ -41,6 +44,15 @@ @ServiceProvider(GraphBuilderPluginsProvider.class) public class TruffleGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + + Registration r2 = new Registration(plugins, metaAccess, OptimizedCallTarget.class); + r2.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) { + builder.push(Kind.Object, builder.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(FrameWithoutBoxing.class)), arg1, arg2))); + return true; + } + }); + Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class); r.register0("inInterpreter", new InvocationPlugin() { public boolean apply(GraphBuilderContext builder) {