OpenJDK / graal / graal-jvmci-8
changeset 6522:c612043278e9
refactoring: graal.compiler.phases -> graal.phases, graal.compiler.virtual -> graal.virtual, graal.compiler.loop -> graal.loop
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Sun, 07 Oct 2012 12:44:05 +0200 |
parents | 2a0c9f20baa1 |
children | c8763a2deb0c |
files | graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/BasicInductionVariable.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/CountedLoopInfo.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/DerivedOffsetInductionVariable.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/DerivedScaledInductionVariable.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/InductionVariable.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/InductionVariables.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopEx.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragment.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInsideBefore.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInsideFrom.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentWhole.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopPolicies.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopTransformations.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopsData.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/phases/loop/LoopFullUnrollPhase.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/phases/loop/LoopTransformHighPhase.java graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/phases/loop/LoopTransformLowPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/OptimisticOptimizations.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/MergeableState.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/package-info.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/package-info.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ComputeProbabilityPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertUnreachedToGuardPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/DeadCodeEliminationPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ExpandBoxingNodesPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/GlobalValueNumberingPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IdentifyBoxingPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InliningPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IntrinsificationPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IterativeCheckCastEliminationPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopSafepointInsertionPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoweringPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/Phase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhasePlan.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhiStampPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/TailDuplicationPhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/BlockClosure.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/SchedulePhase.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/ArrayMap.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BitMap2D.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BlockWorkList.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/GraphOrder.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/InliningUtil.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/IntList.java graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/Util.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/MergeableBlockState.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/PostOrderBlockIterator.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/BlockIteratorClosure.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/EffectList.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/GraphEffectList.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/ReentrantBlockIterator.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/SplitPartialEscapeAnalysisPhase.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/CyclicMaterializeStoreNode.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/MaterializeObjectNode.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/MaterializedObjectState.java graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/BasicInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/CountedLoopInfo.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/DerivedOffsetInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/DerivedScaledInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/InductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/InductionVariables.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopEx.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopFragment.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInsideBefore.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInsideFrom.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopFragmentWhole.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopPolicies.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopTransformations.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/loop/LoopsData.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/phases/loop/LoopFullUnrollPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/phases/loop/LoopTransformHighPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/compiler/phases/loop/LoopTransformLowPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/OptimisticOptimizations.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/graph/MergeableState.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/graph/package-info.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/package-info.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/ComputeProbabilityPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/ConvertUnreachedToGuardPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/DeadCodeEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/ExpandBoxingNodesPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/GlobalValueNumberingPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/IdentifyBoxingPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/InliningPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/IntrinsificationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/IterativeCheckCastEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/LoopSafepointInsertionPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/LoweringPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/Phase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/PhasePlan.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/PhiStampPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/phases/TailDuplicationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/schedule/BlockClosure.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/schedule/SchedulePhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/util/ArrayMap.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/util/BitMap2D.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/util/BlockWorkList.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/util/GraphOrder.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/util/InliningUtil.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/util/IntList.java graal/com.oracle.graal.phases/src/com/oracle/graal/compiler/util/Util.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/MergeableBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/PostOrderBlockIterator.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/BlockIteratorClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/EffectList.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/GraphEffectList.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/ReentrantBlockIterator.java graal/com.oracle.graal.virtual/src/com/oracle/graal/compiler/phases/ea/experimental/SplitPartialEscapeAnalysisPhase.java graal/com.oracle.graal.virtual/src/com/oracle/graal/nodes/virtual/CyclicMaterializeStoreNode.java graal/com.oracle.graal.virtual/src/com/oracle/graal/nodes/virtual/MaterializeObjectNode.java graal/com.oracle.graal.virtual/src/com/oracle/graal/nodes/virtual/MaterializedObjectState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java mx/projects src/share/vm/runtime/arguments.cpp |
diffstat | 140 files changed, 12715 insertions(+), 12715 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/BasicInductionVariable.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.type.*; - - -public class BasicInductionVariable extends InductionVariable { - private PhiNode phi; - private ValueNode init; - private ValueNode rawStride; - private IntegerArithmeticNode op; - - public BasicInductionVariable(LoopEx loop, PhiNode phi, ValueNode init, ValueNode rawStride, IntegerArithmeticNode op) { - super(loop); - this.phi = phi; - this.init = init; - this.rawStride = rawStride; - this.op = op; - } - - @Override - public Direction direction() { - Stamp stamp = rawStride.stamp(); - if (stamp instanceof IntegerStamp) { - IntegerStamp integerStamp = (IntegerStamp) stamp; - Direction dir = null; - if (integerStamp.isStrictlyPositive()) { - dir = Direction.Up; - } else if (integerStamp.isStrictlyNegative()) { - dir = Direction.Down; - } - if (dir != null) { - if (op instanceof IntegerAddNode) { - return dir; - } else { - assert op instanceof IntegerSubNode; - return dir.opposite(); - } - } - } - return null; - } - - @Override - public PhiNode valueNode() { - return phi; - } - - @Override - public ValueNode initNode() { - return init; - } - - @Override - public ValueNode strideNode() { - if (op instanceof IntegerAddNode) { - return rawStride; - } - if (op instanceof IntegerSubNode) { - return rawStride.graph().unique(new NegateNode(rawStride)); - } - throw GraalInternalError.shouldNotReachHere(); - } - - @Override - public boolean isConstantInit() { - return init.isConstant(); - } - - @Override - public boolean isConstantStride() { - return rawStride.isConstant(); - } - - @Override - public long constantInit() { - return init.asConstant().asLong(); - } - - @Override - public long constantStride() { - if (op instanceof IntegerAddNode) { - return rawStride.asConstant().asLong(); - } - if (op instanceof IntegerSubNode) { - return -rawStride.asConstant().asLong(); - } - throw GraalInternalError.shouldNotReachHere(); - } - - @Override - public ValueNode extremumNode() { - return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(strideNode(), loop.counted().maxTripCountNode()), init); - } - - @Override - public boolean isConstantExtremum() { - return isConstantInit() && isConstantStride() && loop.counted().isConstantMaxTripCount(); - } - - @Override - public long constantExtremum() { - return constantStride() * loop.counted().constantMaxTripCount() + constantInit(); - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/CountedLoopInfo.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.compiler.loop.InductionVariable.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - -public class CountedLoopInfo { - private final LoopEx loop; - private InductionVariable iv; - private ValueNode end; - private boolean oneOff; - - CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff) { - this.loop = loop; - this.iv = iv; - this.end = end; - this.oneOff = oneOff; - } - - public ValueNode maxTripCountNode() { - //TODO (gd) stuarte and respect oneOff - return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()), iv.strideNode()); - } - - public boolean isConstantMaxTripCount() { - return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride(); - } - - public long constantMaxTripCount() { - long off = oneOff ? iv.direction() == Direction.Up ? 1 : -1 : 0; - long max = (((ConstantNode) end).asConstant().asLong() + off - iv.constantInit()) / iv.constantStride(); - return Math.max(0, max); - } - - public boolean isExactTripCount() { - return loop.loopBegin().loopExits().count() == 1; - } - - public ValueNode exactTripCountNode() { - assert isExactTripCount(); - return maxTripCountNode(); - } - - public boolean isConstantExactTripCount() { - assert isExactTripCount(); - return isConstantMaxTripCount(); - } - - public long constantExactTripCount() { - assert isExactTripCount(); - return constantMaxTripCount(); - } - - @Override - public String toString() { - return "iv=" + iv + " until " + end + (oneOff ? iv.direction() == Direction.Up ? "+1" : "-1" : ""); - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/DerivedOffsetInductionVariable.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - - -public class DerivedOffsetInductionVariable extends InductionVariable { - private InductionVariable base; - private ValueNode offset; - private IntegerArithmeticNode value; - - public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, IntegerArithmeticNode value) { - super(loop); - this.base = base; - this.offset = offset; - this.value = value; - } - - @Override - public Direction direction() { - return base.direction(); - } - - @Override - public ValueNode valueNode() { - return value; - } - - @Override - public boolean isConstantInit() { - return offset.isConstant() && base.isConstantInit(); - } - - @Override - public boolean isConstantStride() { - return base.isConstantStride(); - } - - @Override - public long constantInit() { - return op(base.constantInit(), offset.asConstant().asLong()); - } - - @Override - public long constantStride() { - if (value instanceof IntegerSubNode && base.valueNode() == value.y()) { - return -base.constantStride(); - } - return base.constantStride(); - } - - @Override - public ValueNode initNode() { - return op(base.initNode(), offset); - } - - @Override - public ValueNode strideNode() { - if (value instanceof IntegerSubNode && base.valueNode() == value.y()) { - return value.graph().unique(new NegateNode(base.strideNode())); - } - return base.strideNode(); - } - - @Override - public ValueNode extremumNode() { - return op(offset, base.extremumNode()); - } - - @Override - public boolean isConstantExtremum() { - return offset.isConstant() && base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return op(base.constantExtremum(), offset.asConstant().asLong()); - } - - private long op(long b, long o) { - if (value instanceof IntegerAddNode) { - return b + o; - } - if (value instanceof IntegerSubNode) { - if (base.valueNode() == value.x()) { - return b - o; - } else { - assert base.valueNode() == value.y(); - return o - b; - } - } - throw GraalInternalError.shouldNotReachHere(); - } - - private ValueNode op(ValueNode b, ValueNode o) { - if (value instanceof IntegerAddNode) { - return IntegerArithmeticNode.add(b, o); - } - if (value instanceof IntegerSubNode) { - if (base.valueNode() == value.x()) { - return IntegerArithmeticNode.sub(b, o); - } else { - assert base.valueNode() == value.y(); - return IntegerArithmeticNode.sub(o, b); - } - } - throw GraalInternalError.shouldNotReachHere(); - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/DerivedScaledInductionVariable.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.type.*; - - -public class DerivedScaledInductionVariable extends InductionVariable { - private InductionVariable base; - private ValueNode scale; - private ValueNode value; - - public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, ValueNode scale, ValueNode value) { - super(loop); - this.base = base; - this.scale = scale; - this.value = value; - } - - public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, NegateNode value) { - super(loop); - this.base = base; - this.scale = ConstantNode.forInt(-1, value.graph()); - this.value = value; - } - - @Override - public Direction direction() { - Stamp stamp = scale.stamp(); - if (stamp instanceof IntegerStamp) { - IntegerStamp integerStamp = (IntegerStamp) stamp; - if (integerStamp.isStrictlyPositive()) { - return base.direction(); - } else if (integerStamp.isStrictlyNegative()) { - return base.direction().opposite(); - } - } - return null; - } - - @Override - public ValueNode valueNode() { - return value; - } - - @Override - public ValueNode initNode() { - return IntegerArithmeticNode.mul(base.initNode(), scale); - } - - @Override - public ValueNode strideNode() { - return IntegerArithmeticNode.mul(base.strideNode(), scale); - } - - @Override - public boolean isConstantInit() { - return scale.isConstant() && base.isConstantInit(); - } - - @Override - public boolean isConstantStride() { - return scale.isConstant() && base.isConstantStride(); - } - - @Override - public long constantInit() { - return base.constantInit() * scale.asConstant().asLong(); - } - - @Override - public long constantStride() { - return base.constantStride() * scale.asConstant().asLong(); - } - - @Override - public ValueNode extremumNode() { - return IntegerArithmeticNode.mul(base.extremumNode(), scale); - } - - @Override - public boolean isConstantExtremum() { - return scale.isConstant() && base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return base.constantExtremum() * scale.asConstant().asLong(); - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/InductionVariable.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - - -public abstract class InductionVariable { - public enum Direction { - Up, - Down; - public Direction opposite() { - switch(this) { - case Up: return Down; - case Down: return Up; - default: throw GraalInternalError.shouldNotReachHere(); - } - } - } - - protected final LoopEx loop; - - public InductionVariable(LoopEx loop) { - this.loop = loop; - } - - public abstract Direction direction(); - - public abstract ValueNode valueNode(); - - public abstract ValueNode initNode(); - public abstract ValueNode strideNode(); - - public abstract boolean isConstantInit(); - public abstract boolean isConstantStride(); - - public abstract long constantInit(); - public abstract long constantStride(); - - public abstract ValueNode extremumNode(); - public abstract boolean isConstantExtremum(); - public abstract long constantExtremum(); -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/InductionVariables.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - - -public class InductionVariables { - private final LoopEx loop; - private Map<Node, InductionVariable> ivs; - - public InductionVariables(LoopEx loop) { - this.loop = loop; - ivs = new IdentityHashMap<>(); - findDerived(findBasic()); - } - - public InductionVariable get(ValueNode v) { - return ivs.get(v); - } - - private Collection<BasicInductionVariable> findBasic() { - List<BasicInductionVariable> bivs = new LinkedList<>(); - LoopBeginNode loopBegin = loop.loopBegin(); - EndNode forwardEnd = loopBegin.forwardEnd(); - for (PhiNode phi : loopBegin.phis()) { - ValueNode backValue = phi.singleBackValue(); - if (backValue == null) { - continue; - } - ValueNode stride = addSub(backValue, phi); - if (stride != null) { - BasicInductionVariable biv = new BasicInductionVariable(loop, phi, phi.valueAt(forwardEnd), stride, (IntegerArithmeticNode) backValue); - ivs.put(phi, biv); - bivs.add(biv); - } - } - return bivs; - } - - private void findDerived(Collection<BasicInductionVariable> bivs) { - Queue<InductionVariable> scanQueue = new LinkedList<InductionVariable>(bivs); - while (!scanQueue.isEmpty()) { - InductionVariable baseIv = scanQueue.remove(); - ValueNode baseIvNode = baseIv.valueNode(); - for (ValueNode op : baseIvNode.usages().filter(ValueNode.class)) { - if (loop.isOutsideLoop(op)) { - continue; - } - InductionVariable iv = null; - ValueNode offset = addSub(op, baseIvNode); - ValueNode scale; - if (offset != null) { - iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (IntegerArithmeticNode) op); - } else if (op instanceof NegateNode) { - iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op); - } else if ((scale = mul(op, baseIvNode)) != null) { - iv = new DerivedScaledInductionVariable(loop, baseIv, scale, op); - } - - if (iv != null) { - ivs.put(op, iv); - scanQueue.offer(iv); - } - } - } - } - - private ValueNode addSub(ValueNode op, ValueNode base) { - if (op instanceof IntegerAddNode || op instanceof IntegerSubNode) { - IntegerArithmeticNode aritOp = (IntegerArithmeticNode) op; - if (aritOp.x() == base && loop.isOutsideLoop(aritOp.y())) { - return aritOp.y(); - } else if (aritOp.y() == base && loop.isOutsideLoop(aritOp.x())) { - return aritOp.x(); - } - } - return null; - } - - private ValueNode mul(ValueNode op, ValueNode base) { - if (op instanceof IntegerMulNode) { - IntegerMulNode mul = (IntegerMulNode) op; - if (mul.x() == base && loop.isOutsideLoop(mul.y())) { - return mul.y(); - } else if (mul.y() == base && loop.isOutsideLoop(mul.x())) { - return mul.x(); - } - } - if (op instanceof LeftShiftNode) { - LeftShiftNode shift = (LeftShiftNode) op; - if (shift.x() == base && shift.y().isConstant()) { - return ConstantNode.forInt(1 << shift.y().asConstant().asInt(), base.graph()); - } - } - return null; - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopEx.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - -public class LoopEx { - private final Loop lirLoop; - private LoopFragmentInside inside; - private LoopFragmentWhole whole; - private CountedLoopInfo counted; //TODO (gd) detect - private LoopsData data; - - LoopEx(Loop lirLoop, LoopsData data) { - this.lirLoop = lirLoop; - this.data = data; - } - - public Loop lirLoop() { - return lirLoop; - } - - public LoopFragmentInside inside() { - if (inside == null) { - inside = new LoopFragmentInside(this); - } - return inside; - } - - public LoopFragmentWhole whole() { - if (whole == null) { - whole = new LoopFragmentWhole(this); - } - return whole; - } - - @SuppressWarnings("unused") - public LoopFragmentInsideFrom insideFrom(FixedNode point) { - // TODO (gd) - return null; - } - - @SuppressWarnings("unused") - public LoopFragmentInsideBefore insideBefore(FixedNode point) { - // TODO (gd) - return null; - } - - public boolean isOutsideLoop(Node n) { - return !whole().contains(n); - } - - public LoopBeginNode loopBegin() { - return lirLoop().loopBegin(); - } - - public FixedNode predecessor() { - return (FixedNode) loopBegin().forwardEnd().predecessor(); - } - - public FixedNode entryPoint() { - return loopBegin().forwardEnd(); - } - - public boolean isCounted() { - return counted != null; - } - - public CountedLoopInfo counted() { - return counted; - } - - public LoopEx parent() { - if (lirLoop.parent == null) { - return null; - } - return data.loop(lirLoop.parent); - } - - public int size() { - return whole().nodes().count(); - } - - @Override - public String toString() { - return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + lirLoop().depth + ") " + loopBegin(); - } - - private class InvariantPredicate extends NodePredicate { - @Override - public boolean apply(Node n) { - return isOutsideLoop(n); - } - } - - public void reassociateInvariants() { - InvariantPredicate invariant = new InvariantPredicate(); - StructuredGraph graph = (StructuredGraph) loopBegin().graph(); - for (BinaryNode binary : whole().nodes().filter(BinaryNode.class)) { - if (!BinaryNode.canTryReassociate(binary)) { - continue; - } - BinaryNode result = BinaryNode.reassociate(binary, invariant); - if (result != binary) { - Debug.log(MetaUtil.format("%H::%n", Debug.contextLookup(ResolvedJavaMethod.class)) + " : Reassociated %s into %s", binary, result); - graph.replaceFloating(binary, result); - } - } - } - - public void setCounted(CountedLoopInfo countedLoopInfo) { - counted = countedLoopInfo; - } - - public LoopsData loopsData() { - return data; - } - - public NodeBitMap nodesInLoopFrom(BeginNode point, BeginNode until) { - Collection<BeginNode> blocks = new LinkedList<>(); - Collection<BeginNode> exits = new LinkedList<>(); - Queue<Block> work = new LinkedList<>(); - ControlFlowGraph cfg = loopsData().controlFlowGraph(); - work.add(cfg.blockFor(point)); - Block untilBlock = until != null ? cfg.blockFor(until) : null; - while (!work.isEmpty()) { - Block b = work.remove(); - if (b == untilBlock) { - continue; - } - if (lirLoop().exits.contains(b)) { - exits.add(b.getBeginNode()); - } else if (lirLoop().blocks.contains(b)) { - blocks.add(b.getBeginNode()); - work.addAll(b.getDominated()); - } - } - return LoopFragment.computeNodes(point.graph(), blocks, exits); - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragment.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.VirtualState.VirtualClosure; - - -public abstract class LoopFragment { - private final LoopEx loop; - private final LoopFragment original; - protected NodeBitMap nodes; - protected boolean nodesReady; - private Map<Node, Node> duplicationMap; - - public LoopFragment(LoopEx loop) { - this(loop, null); - this.nodesReady = true; - } - - public LoopFragment(LoopEx loop, LoopFragment original) { - this.loop = loop; - this.original = original; - this.nodesReady = false; - } - - public LoopEx loop() { - return loop; - } - - public abstract LoopFragment duplicate(); - - public abstract void insertBefore(LoopEx l); - - public void disconnect() { - // TODO (gd) possibly abstract - } - - public boolean contains(Node n) { - return nodes().contains(n); - } - - @SuppressWarnings("unchecked") - public <New extends Node, Old extends New> New getDuplicatedNode(Old n) { - assert isDuplicate(); - return (New) duplicationMap.get(n); - } - - protected <New extends Node, Old extends New> void putDuplicatedNode(Old oldNode, New newNode) { - duplicationMap.put(oldNode, newNode); - } - - public boolean isDuplicate() { - return original != null; - } - - public LoopFragment original() { - return original; - } - - public abstract NodeIterable<Node> nodes(); - - public StructuredGraph graph() { - LoopEx l; - if (isDuplicate()) { - l = original().loop(); - } else { - l = loop(); - } - return (StructuredGraph) l.loopBegin().graph(); - } - - protected abstract DuplicationReplacement getDuplicationReplacement(); - - protected abstract void finishDuplication(); - - protected void patchNodes(final DuplicationReplacement dataFix) { - if (isDuplicate() && !nodesReady) { - assert !original.isDuplicate(); - final DuplicationReplacement cfgFix = original().getDuplicationReplacement(); - DuplicationReplacement dr; - if (cfgFix == null && dataFix != null) { - dr = dataFix; - } else if (cfgFix != null && dataFix == null) { - dr = cfgFix; - } else if (cfgFix != null && dataFix != null) { - dr = new DuplicationReplacement() { - @Override - public Node replacement(Node o) { - Node r1 = dataFix.replacement(o); - if (r1 != o) { - assert cfgFix.replacement(o) == o; - return r1; - } - Node r2 = cfgFix.replacement(o); - if (r2 != o) { - return r2; - } - return o; - } - }; - } else { - dr = new DuplicationReplacement() { - @Override - public Node replacement(Node o) { - return o; - } - }; - } - duplicationMap = graph().addDuplicates(original().nodes(), dr); - finishDuplication(); - nodesReady = true; - } else { - //TODO (gd) apply fix ? - } - } - - protected static NodeBitMap computeNodes(Graph graph, Collection<BeginNode> blocks) { - return computeNodes(graph, blocks, Collections.<BeginNode>emptyList()); - } - - protected static NodeBitMap computeNodes(Graph graph, Collection<BeginNode> blocks, Collection<BeginNode> earlyExits) { - final NodeBitMap nodes = graph.createNodeBitMap(true); - for (BeginNode b : blocks) { - for (Node n : b.getBlockNodes()) { - if (n instanceof Invoke) { - nodes.mark(((Invoke) n).callTarget()); - } - if (n instanceof StateSplit) { - FrameState stateAfter = ((StateSplit) n).stateAfter(); - if (stateAfter != null) { - nodes.mark(stateAfter); - } - } - nodes.mark(n); - } - } - for (BeginNode earlyExit : earlyExits) { - FrameState stateAfter = earlyExit.stateAfter(); - if (stateAfter != null) { - nodes.mark(stateAfter); - stateAfter.applyToVirtual(new VirtualClosure() { - @Override - public void apply(VirtualState node) { - nodes.mark(node); - } - }); - } - nodes.mark(earlyExit); - for (ValueProxyNode proxy : earlyExit.proxies()) { - nodes.mark(proxy); - } - } - - for (BeginNode b : blocks) { - for (Node n : b.getBlockNodes()) { - for (Node usage : n.usages()) { - markFloating(usage, nodes); - } - } - } - - return nodes; - } - - private static boolean markFloating(Node n, NodeBitMap loopNodes) { - if (loopNodes.isMarked(n)) { - return true; - } - if (n instanceof FixedNode) { - return false; - } - boolean mark = false; - if (n instanceof PhiNode) { - PhiNode phi = (PhiNode) n; - mark = loopNodes.isMarked(phi.merge()); - if (mark) { - loopNodes.mark(n); - } else { - return false; - } - } - for (Node usage : n.usages()) { - if (markFloating(usage, loopNodes)) { - mark = true; - } - } - if (mark) { - loopNodes.mark(n); - return true; - } - return false; - } - - public static Collection<BeginNode> toHirBlocks(Collection<Block> blocks) { - List<BeginNode> hir = new ArrayList<>(blocks.size()); - for (Block b : blocks) { - hir.add(b.getBeginNode()); - } - return hir; - } - - /** - * Merges the early exits (i.e. loop exits) that were duplicated as part of this fragment, with the original fragment's exits. - */ - protected void mergeEarlyExits() { - assert isDuplicate(); - StructuredGraph graph = graph(); - for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) { - FixedNode next = earlyExit.next(); - if (earlyExit.isDeleted() || !this.original().contains(earlyExit)) { - continue; - } - BeginNode newEarlyExit = getDuplicatedNode(earlyExit); - if (newEarlyExit == null) { - continue; - } - MergeNode merge = graph.add(new MergeNode()); - merge.setProbability(next.probability()); - EndNode originalEnd = graph.add(new EndNode()); - EndNode newEnd = graph.add(new EndNode()); - merge.addForwardEnd(originalEnd); - merge.addForwardEnd(newEnd); - earlyExit.setNext(originalEnd); - newEarlyExit.setNext(newEnd); - merge.setNext(next); - - FrameState exitState = earlyExit.stateAfter(); - FrameState newExitState = newEarlyExit.stateAfter(); - FrameState state = null; - if (exitState != null) { - state = exitState.duplicateWithVirtualState(); - merge.setStateAfter(state); - } - - for (Node anchored : earlyExit.anchored().snapshot()) { - anchored.replaceFirstInput(earlyExit, merge); - } - - for (final ValueProxyNode vpn : earlyExit.proxies().snapshot()) { - final ValueNode replaceWith; - ValueProxyNode newVpn = getDuplicatedNode(vpn); - if (newVpn != null) { - PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge)); - phi.addInput(vpn); - phi.addInput(newVpn); - replaceWith = phi; - } else { - replaceWith = vpn.value(); - } - if (state != null) { - state.applyToNonVirtual(new NodeClosure<ValueNode>() { - @Override - public void apply(Node from, ValueNode node) { - if (node == vpn) { - from.replaceFirstInput(vpn, replaceWith); - } - } - }); - } - for (Node usage : vpn.usages().snapshot()) { - if (!merge.isPhiAtMerge(usage)) { - if (usage instanceof VirtualState) { - VirtualState stateUsage = (VirtualState) usage; - if (exitState.isPartOfThisState(stateUsage) || newExitState.isPartOfThisState(stateUsage)) { - continue; - } - } - usage.replaceFirstInput(vpn, replaceWith); - } - } - } - } - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.util.*; - - -public class LoopFragmentInside extends LoopFragment { - /** mergedInitializers. - * When an inside fragment's (loop)ends are merged to create a unique exit point, - * some phis must be created : they phis together all the back-values of the loop-phis - * These can then be used to update the loop-phis' forward edge value ('initializer') in the peeling case. - * In the unrolling case they will be used as the value that replace the loop-phis of the duplicated inside fragment - */ - private Map<PhiNode, ValueNode> mergedInitializers; - private final DuplicationReplacement dataFixBefore = new DuplicationReplacement() { - @Override - public Node replacement(Node oriInput) { - if (!(oriInput instanceof ValueNode)) { - return oriInput; - } - return prim((ValueNode) oriInput); - } - }; - - public LoopFragmentInside(LoopEx loop) { - super(loop); - } - - public LoopFragmentInside(LoopFragmentInside original) { - super(null, original); - } - - @Override - public LoopFragmentInside duplicate() { - assert !isDuplicate(); - return new LoopFragmentInside(this); - } - - @Override - public LoopFragmentInside original() { - return (LoopFragmentInside) super.original(); - } - - @SuppressWarnings("unused") - public void appendInside(LoopEx loop) { - // TODO (gd) - } - - @Override - public LoopEx loop() { - assert !this.isDuplicate(); - return super.loop(); - } - - @Override - public void insertBefore(LoopEx loop) { - assert this.isDuplicate() && this.original().loop() == loop; - - patchNodes(dataFixBefore); - - BeginNode end = mergeEnds(); - - original().patchPeeling(this); - - mergeEarlyExits(); - - BeginNode entry = getDuplicatedNode(loop.loopBegin()); - FrameState state = entry.stateAfter(); - if (state != null) { - entry.setStateAfter(null); - GraphUtil.killWithUnusedFloatingInputs(state); - } - loop.entryPoint().replaceAtPredecessor(entry); - end.setProbability(loop.entryPoint().probability()); - end.setNext(loop.entryPoint()); - } - - @Override - public NodeIterable<Node> nodes() { - if (nodes == null) { - LoopFragmentWhole whole = loop().whole(); - whole.nodes(); // init nodes bitmap in whole - nodes = whole.nodes.copy(); - // remove the phis - for (PhiNode phi : loop().loopBegin().phis()) { - nodes.clear(phi); - } - } - return nodes; - } - - @Override - protected DuplicationReplacement getDuplicationReplacement() { - final LoopBeginNode loopBegin = loop().loopBegin(); - final StructuredGraph graph = graph(); - return new DuplicationReplacement() { - @Override - public Node replacement(Node original) { - if (original == loopBegin) { - return graph.add(new BeginNode()); - } - if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) { - return graph.add(new BeginNode()); - } - if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) { - return graph.add(new EndNode()); - } - return original; - } - }; - } - - @Override - protected void finishDuplication() { - // TODO (gd) ? - } - - private void patchPeeling(LoopFragmentInside peel) { - LoopBeginNode loopBegin = loop().loopBegin(); - StructuredGraph graph = (StructuredGraph) loopBegin.graph(); - List<PhiNode> newPhis = new LinkedList<>(); - for (PhiNode phi : loopBegin.phis().snapshot()) { - ValueNode first; - if (loopBegin.loopEnds().count() == 1) { - ValueNode b = phi.valueAt(loopBegin.loopEnds().first()); // back edge value - first = peel.prim(b); // corresponding value in the peel - } else { - first = peel.mergedInitializers.get(phi); - } - // create a new phi (we don't patch the old one since some usages of the old one may still be valid) - PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin)); - newPhi.addInput(first); - for (LoopEndNode end : loopBegin.orderedLoopEnds()) { - newPhi.addInput(phi.valueAt(end)); - } - peel.putDuplicatedNode(phi, newPhi); - newPhis.add(newPhi); - for (Node usage : phi.usages().snapshot()) { - if (peel.getDuplicatedNode(usage) != null) { // patch only usages that should use the new phi ie usages that were peeled - usage.replaceFirstInput(phi, newPhi); - } - } - } - // check new phis to see if they have as input some old phis, replace those inputs with the new corresponding phis - for (PhiNode phi : newPhis) { - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode v = phi.valueAt(i); - if (loopBegin.isPhiAtMerge(v)) { - PhiNode newV = peel.getDuplicatedNode((PhiNode) v); - if (newV != null) { - phi.setValueAt(i, newV); - } - } - } - } - } - - /** - * Gets the corresponding value in this fragment. - * - * @param b original value - * @return corresponding value in the peel - */ - private ValueNode prim(ValueNode b) { - assert isDuplicate(); - LoopBeginNode loopBegin = original().loop().loopBegin(); - if (loopBegin.isPhiAtMerge(b)) { - PhiNode phi = (PhiNode) b; - return phi.valueAt(loopBegin.forwardEnd()); - } else if (nodesReady) { - ValueNode v = getDuplicatedNode(b); - if (v == null) { - return b; - } - return v; - } else { - return b; - } - } - - private BeginNode mergeEnds() { - assert isDuplicate(); - List<EndNode> endsToMerge = new LinkedList<>(); - Map<EndNode, LoopEndNode> reverseEnds = new HashMap<>(); // map peel's exit to the corresponding loop exits - LoopBeginNode loopBegin = original().loop().loopBegin(); - for (LoopEndNode le : loopBegin.loopEnds()) { - EndNode duplicate = getDuplicatedNode(le); - if (duplicate != null) { - endsToMerge.add(duplicate); - reverseEnds.put(duplicate, le); - } - } - mergedInitializers = new IdentityHashMap<>(); - BeginNode newExit; - StructuredGraph graph = graph(); - if (endsToMerge.size() == 1) { - EndNode end = endsToMerge.get(0); - assert end.usages().count() == 0; - newExit = graph.add(new BeginNode()); - end.replaceAtPredecessor(newExit); - end.safeDelete(); - } else { - assert endsToMerge.size() > 1; - MergeNode newExitMerge = graph.add(new MergeNode()); - newExit = newExitMerge; - FrameState state = loopBegin.stateAfter(); - FrameState duplicateState = null; - if (state != null) { - duplicateState = state.duplicateWithVirtualState(); - newExitMerge.setStateAfter(duplicateState); - } - for (EndNode end : endsToMerge) { - newExitMerge.addForwardEnd(end); - } - - for (final PhiNode phi : loopBegin.phis().snapshot()) { - final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge)); - for (EndNode end : newExitMerge.forwardEnds()) { - LoopEndNode loopEnd = reverseEnds.get(end); - ValueNode prim = prim(phi.valueAt(loopEnd)); - assert prim != null; - firstPhi.addInput(prim); - } - ValueNode initializer = firstPhi; - if (duplicateState != null) { - // fix the merge's state after - duplicateState.applyToNonVirtual(new NodeClosure<ValueNode>() { - @Override - public void apply(Node from, ValueNode node) { - if (node == phi) { - from.replaceFirstInput(phi, firstPhi); - } - } - }); - } - mergedInitializers.put(phi, initializer); - } - } - return newExit; - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInsideBefore.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; - - -public class LoopFragmentInsideBefore extends LoopFragmentInside { - private final FixedNode point; - - public LoopFragmentInsideBefore(LoopEx loop, FixedNode point) { - super(loop); - this.point = point; - } - - // duplicates lazily - public LoopFragmentInsideBefore(LoopFragmentInsideBefore original) { - super(original); - this.point = original.point(); - } - - public FixedNode point() { - return point; - } - - @Override - public LoopFragmentInsideBefore duplicate() { - return new LoopFragmentInsideBefore(this); - } - - @Override - public NodeIterable<Node> nodes() { - // TODO Auto-generated method stub - return null; - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentInsideFrom.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; - - -public class LoopFragmentInsideFrom extends LoopFragmentInside { - private final FixedNode point; - - public LoopFragmentInsideFrom(LoopEx loop, FixedNode point) { - super(loop); - this.point = point; - } - - // duplicates lazily - public LoopFragmentInsideFrom(LoopFragmentInsideFrom original) { - super(original); - this.point = original.point(); - } - - public FixedNode point() { - return point; - } - - @Override - public LoopFragmentInsideFrom duplicate() { - return new LoopFragmentInsideFrom(this); - } - - @Override - public NodeIterable<Node> nodes() { - // TODO Auto-generated method stub - return null; - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopFragmentWhole.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - - -public class LoopFragmentWhole extends LoopFragment { - - public LoopFragmentWhole(LoopEx loop) { - super(loop); - } - - public LoopFragmentWhole(LoopFragmentWhole original) { - super(null, original); - } - - @Override - public LoopFragmentWhole duplicate() { - LoopFragmentWhole loopFragmentWhole = new LoopFragmentWhole(this); - loopFragmentWhole.reify(); - return loopFragmentWhole; - } - - private void reify() { - assert this.isDuplicate(); - - patchNodes(null); - - mergeEarlyExits(); - } - - @Override - public NodeIterable<Node> nodes() { - if (nodes == null) { - Loop lirLoop = loop().lirLoop(); - nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.blocks), LoopFragment.toHirBlocks(lirLoop.exits)); - } - return nodes; - } - - @Override - protected DuplicationReplacement getDuplicationReplacement() { - final FixedNode entry = loop().entryPoint(); - final Graph graph = this.graph(); - return new DuplicationReplacement() { - @Override - public Node replacement(Node o) { - if (o == entry) { - return graph.add(new EndNode()); - } - return o; - } - }; - } - - public FixedNode entryPoint() { - if (isDuplicate()) { - LoopBeginNode newLoopBegin = getDuplicatedNode(original().loop().loopBegin()); - return newLoopBegin.forwardEnd(); - } - return loop().entryPoint(); - } - - @Override - protected void finishDuplication() { - // TODO (gd) ? - } - - @Override - public void insertBefore(LoopEx loop) { - // TODO Auto-generated method stub - - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopPolicies.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - - -public abstract class LoopPolicies { - private LoopPolicies() { - // does not need to be instantiated - } - - // TODO (gd) change when inversion is available - public static boolean shouldPeel(LoopEx loop) { - LoopBeginNode loopBegin = loop.loopBegin(); - double entryProbability = loopBegin.forwardEnd().probability(); - return entryProbability > GraalOptions.MinimumPeelProbability && loop.size() + loopBegin.graph().getNodeCount() < GraalOptions.MaximumDesiredSize; - } - - public static boolean shouldFullUnroll(LoopEx loop) { - if (!loop.isCounted() || !loop.counted().isConstantMaxTripCount()) { - return false; - } - CountedLoopInfo counted = loop.counted(); - long exactTrips = counted.constantMaxTripCount(); - int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? GraalOptions.ExactFullUnrollMaxNodes : GraalOptions.FullUnrollMaxNodes; - maxNodes = Math.min(maxNodes, GraalOptions.MaximumDesiredSize - loop.loopBegin().graph().getNodeCount()); - int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count()); - return size * exactTrips <= maxNodes; - } - - public static boolean shouldTryUnswitch(LoopEx loop) { - return loop.loopBegin().unswitches() <= GraalOptions.LoopMaxUnswitch; - } - - public static boolean shouldUnswitch(LoopEx loop, IfNode ifNode) { - Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(ifNode).getPostdominator(); - BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null; - int inTrueBranch = loop.nodesInLoopFrom(ifNode.trueSuccessor(), postDom).cardinality(); - int inFalseBranch = loop.nodesInLoopFrom(ifNode.falseSuccessor(), postDom).cardinality(); - int loopTotal = loop.size(); - int netDiff = loopTotal - (inTrueBranch + inFalseBranch); - double uncertainty = (0.5 - Math.abs(ifNode.probability(IfNode.TRUE_EDGE) - 0.5)) * 2; - int maxDiff = GraalOptions.LoopUnswitchMaxIncrease + (int) (GraalOptions.LoopUnswitchUncertaintyBoost * loop.loopBegin().loopFrequency() * uncertainty); - Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of if", loop, ifNode, netDiff, maxDiff, (double) (inTrueBranch + inFalseBranch) / loopTotal * 100); - return netDiff <= maxDiff; - } - - -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopTransformations.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.util.*; - - -public abstract class LoopTransformations { - private static final int UNROLL_LIMIT = GraalOptions.FullUnrollMaxNodes * 2; - private static final SimplifierTool simplifier = new SimplifierTool() { - @Override - public TargetDescription target() { - return null; - } - @Override - public CodeCacheProvider runtime() { - return null; - } - @Override - public boolean isImmutable(Constant objectConstant) { - return false; - } - @Override - public Assumptions assumptions() { - return null; - } - @Override - public void deleteBranch(FixedNode branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch); - } - @Override - public void addToWorkList(Node node) { - } - }; - - private LoopTransformations() { - // does not need to be instantiated - } - - public static void invert(LoopEx loop, FixedNode point) { - LoopFragmentInsideBefore head = loop.insideBefore(point); - LoopFragmentInsideBefore duplicate = head.duplicate(); - head.disconnect(); - head.insertBefore(loop); - duplicate.appendInside(loop); - } - - public static void peel(LoopEx loop) { - loop.inside().duplicate().insertBefore(loop); - } - - public static void fullUnroll(LoopEx loop, MetaAccessProvider runtime) { - //assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count - int iterations = 0; - LoopBeginNode loopBegin = loop.loopBegin(); - StructuredGraph graph = (StructuredGraph) loopBegin.graph(); - while (!loopBegin.isDeleted()) { - int mark = graph.getMark(); - peel(loop); - new CanonicalizerPhase(null, runtime, null, mark, null).apply(graph); - if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > GraalOptions.MaximumDesiredSize * 3) { - throw new BailoutException("FullUnroll : Graph seems to grow out of proportion"); - } - } - } - - public static void unswitch(LoopEx loop, IfNode ifNode) { - // duplicate will be true case, original will be false case - loop.loopBegin().incUnswitches(); - LoopFragmentWhole originalLoop = loop.whole(); - LoopFragmentWhole duplicateLoop = originalLoop.duplicate(); - StructuredGraph graph = (StructuredGraph) ifNode.graph(); - BeginNode tempBegin = graph.add(new BeginNode()); - originalLoop.entryPoint().replaceAtPredecessor(tempBegin); - double takenProbability = ifNode.probability(ifNode.blockSuccessorIndex(ifNode.trueSuccessor())); - IfNode newIf = graph.add(new IfNode(ifNode.compare(), duplicateLoop.entryPoint(), originalLoop.entryPoint(), takenProbability, ifNode.leafGraphId())); - tempBegin.setNext(newIf); - ifNode.setCompare(graph.unique(ConstantNode.forBoolean(false, graph))); - IfNode duplicateIf = duplicateLoop.getDuplicatedNode(ifNode); - duplicateIf.setCompare(graph.unique(ConstantNode.forBoolean(true, graph))); - ifNode.simplify(simplifier); - duplicateIf.simplify(simplifier); - // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms) - } - - public static void unroll(LoopEx loop, int factor) { - assert loop.isCounted(); - if (factor > 0) { - throw new UnsupportedOperationException(); - } - // TODO (gd) implement counted loop - LoopFragmentWhole main = loop.whole(); - LoopFragmentWhole prologue = main.duplicate(); - prologue.insertBefore(loop); - //CountedLoopBeginNode counted = prologue.countedLoop(); - //StructuredGraph graph = (StructuredGraph) counted.graph(); - //ValueNode tripCountPrologue = counted.tripCount(); - //ValueNode tripCountMain = counted.tripCount(); - //graph.replaceFloating(tripCountPrologue, "tripCountPrologue % factor"); - //graph.replaceFloating(tripCountMain, "tripCountMain - (tripCountPrologue % factor)"); - LoopFragmentInside inside = loop.inside(); - for (int i = 0; i < factor; i++) { - inside.duplicate().appendInside(loop); - } - } - - public static IfNode findUnswitchableIf(LoopEx loop) { - for (IfNode ifNode : loop.whole().nodes().filter(IfNode.class)) { - if (loop.isOutsideLoop(ifNode.compare())) { - return ifNode; - } - } - return null; - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/loop/LoopsData.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.compiler.loop.InductionVariable.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - -public class LoopsData { - private Map<Loop, LoopEx> lirLoopToEx = new IdentityHashMap<>(); - private Map<LoopBeginNode, LoopEx> loopBeginToEx = new IdentityHashMap<>(); - private ControlFlowGraph cfg; - - public LoopsData(final StructuredGraph graph) { - - cfg = Debug.scope("ControlFlowGraph", new Callable<ControlFlowGraph>() { - @Override - public ControlFlowGraph call() throws Exception { - return ControlFlowGraph.compute(graph, true, true, true, true); - } - }); - for (Loop lirLoop : cfg.getLoops()) { - LoopEx ex = new LoopEx(lirLoop, this); - lirLoopToEx.put(lirLoop, ex); - loopBeginToEx.put(ex.loopBegin(), ex); - } - } - - public LoopEx loop(Loop lirLoop) { - return lirLoopToEx.get(lirLoop); - } - - public LoopEx loop(LoopBeginNode loopBegin) { - return loopBeginToEx.get(loopBegin); - } - - public Collection<LoopEx> loops() { - return lirLoopToEx.values(); - } - - public List<LoopEx> outterFirst() { - ArrayList<LoopEx> loops = new ArrayList<>(loops()); - Collections.sort(loops, new Comparator<LoopEx>() { - @Override - public int compare(LoopEx o1, LoopEx o2) { - return o1.lirLoop().depth - o2.lirLoop().depth; - } - }); - return loops; - } - - public Collection<LoopEx> countedLoops() { - List<LoopEx> counted = new LinkedList<>(); - for (LoopEx loop : loops()) { - if (loop.isCounted()) { - counted.add(loop); - } - } - return counted; - } - - public void detectedCountedLoops() { - for (LoopEx loop : loops()) { - InductionVariables ivs = new InductionVariables(loop); - LoopBeginNode loopBegin = loop.loopBegin(); - FixedNode next = loopBegin.next(); - if (next instanceof IfNode) { - IfNode ifNode = (IfNode) next; - boolean negated = false; - if (!loopBegin.isLoopExit(ifNode.falseSuccessor())) { - if (!loopBegin.isLoopExit(ifNode.trueSuccessor())) { - continue; - } - negated = true; - } - BooleanNode ifTest = ifNode.compare(); - if (!(ifTest instanceof IntegerLessThanNode)) { - if (ifTest instanceof IntegerBelowThanNode) { - Debug.log("Ignored potential Counted loop at %s with |<|", loopBegin); - } - continue; - } - IntegerLessThanNode lessThan = (IntegerLessThanNode) ifTest; - Condition condition = null; - InductionVariable iv = null; - ValueNode limit = null; - if (loop.isOutsideLoop(lessThan.x())) { - iv = ivs.get(lessThan.y()); - if (iv != null) { - condition = lessThan.condition().mirror(); - limit = lessThan.x(); - } - } else if (loop.isOutsideLoop(lessThan.y())) { - iv = ivs.get(lessThan.x()); - if (iv != null) { - condition = lessThan.condition(); - limit = lessThan.y(); - } - } - if (condition == null) { - continue; - } - if (negated) { - condition = condition.negate(); - } - boolean oneOff = false; - switch (condition) { - case LE: - oneOff = true; // fall through - case LT: - if (iv.direction() != Direction.Up) { - continue; - } - break; - case GE: - oneOff = true; // fall through - case GT: - if (iv.direction() != Direction.Down) { - continue; - } - break; - default: throw GraalInternalError.shouldNotReachHere(); - } - loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff)); - } - } - } - - public ControlFlowGraph controlFlowGraph() { - return cfg; - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/phases/loop/LoopFullUnrollPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases.loop; - -import com.oracle.graal.compiler.loop.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - - -public class LoopFullUnrollPhase extends Phase { - private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls"); - private final GraalCodeCacheProvider runtime; - - public LoopFullUnrollPhase(GraalCodeCacheProvider runtime) { - this.runtime = runtime; - } - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - boolean peeled; - do { - peeled = false; - final LoopsData dataCounted = new LoopsData(graph); - dataCounted.detectedCountedLoops(); - for (LoopEx loop : dataCounted.countedLoops()) { - if (LoopPolicies.shouldFullUnroll(loop)) { - Debug.log("FullUnroll %s", loop); - LoopTransformations.fullUnroll(loop, runtime); - FULLY_UNROLLED_LOOPS.increment(); - Debug.dump(graph, "After fullUnroll %s", loop); - peeled = true; - break; - } - } - } while(peeled); - } - } - -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/phases/loop/LoopTransformHighPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases.loop; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.loop.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; - -public class LoopTransformHighPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - if (GraalOptions.LoopPeeling) { - LoopsData data = new LoopsData(graph); - for (LoopEx loop : data.outterFirst()) { - if (LoopPolicies.shouldPeel(loop)) { - Debug.log("Peeling %s", loop); - LoopTransformations.peel(loop); - Debug.dump(graph, "After peeling %s", loop); - } - } - } - } - } -}
--- a/graal/com.oracle.graal.compiler.loop/src/com/oracle/graal/compiler/phases/loop/LoopTransformLowPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases.loop; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.loop.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; - -public class LoopTransformLowPhase extends Phase { - private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched"); - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - if (GraalOptions.ReassociateInvariants) { - final LoopsData dataReassociate = new LoopsData(graph); - Debug.scope("ReassociateInvariants", new Runnable() { - @Override - public void run() { - for (LoopEx loop : dataReassociate.loops()) { - loop.reassociateInvariants(); - } - } - }); - } - if (GraalOptions.LoopUnswitch) { - boolean unswitched; - do { - unswitched = false; - final LoopsData dataUnswitch = new LoopsData(graph); - for (LoopEx loop : dataUnswitch.loops()) { - if (LoopPolicies.shouldTryUnswitch(loop)) { - IfNode ifNode = LoopTransformations.findUnswitchableIf(loop); - if (ifNode != null && LoopPolicies.shouldUnswitch(loop, ifNode)) { - Debug.log("Unswitching %s at %s [%f - %f]", loop, ifNode, ifNode.probability(0), ifNode.probability(1)); - LoopTransformations.unswitch(loop, ifNode); - UNSWITCHED.increment(); - Debug.dump(graph, "After unswitch %s", loop); - unswitched = true; - break; - } - } - } - } while(unswitched); - } - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler; - - - -/** - * This class encapsulates options that control the behavior of the Graal compiler. - * - * (thomaswue) WARNING: Fields of this class are treated as final by Graal. - */ -public final class GraalOptions { - - // Checkstyle: stop - private static final boolean ____ = false; - // Checkstyle: resume - - public static int Threads = 4; - - // inlining settings - public static boolean Inline = true; - public static boolean Intrinsify = true; - static boolean InlineMonomorphicCalls = true; - static boolean InlinePolymorphicCalls = true; - static boolean InlineMegamorphicCalls = ____; - public static int InliningPolicy = 4; - public static int WeightComputationPolicy = 2; - public static int MaximumTrivialSize = 10; - public static int MaximumInlineLevel = 30; - public static int MaximumDesiredSize = 3000; - public static int MaximumRecursiveInlining = 1; - public static int SmallCompiledCodeSize = 2000; - public static boolean LimitInlinedProbability = ____; - // WeightBasedInliningPolicy (0) - public static boolean ParseBeforeInlining = ____; - public static float InliningSizePenaltyExp = 20; - public static float MaximumInlineWeight = 1.25f; - public static float InliningSizePenalty = 1; - // StaticSizeBasedInliningPolicy (1), MinimumCodeSizeBasedInlining (2), - // DynamicSizeBasedInliningPolicy (3) - public static int MaximumInlineSize = 35; - // GreedySizeBasedInlining (4) - public static int MaximumGreedyInlineSize = 100; - public static int InliningBonusPerTransferredValue = 10; - // Common options for inlining policies 1 to 4 - public static float NestedInliningSizeRatio = 1f; - public static float BoostInliningForEscapeAnalysis = 2f; - public static float ProbabilityCapForInlining = 1f; - - // escape analysis settings - public static boolean PartialEscapeAnalysis = true; - - public static double TailDuplicationProbability = 0.5; - public static int TailDuplicationTrivialSize = 1; - - // absolute probability analysis - public static boolean ProbabilityAnalysis = true; - public static int LoopFrequencyPropagationPolicy = -2; - - // profiling information - public static int DeoptsToDisableOptimisticOptimization = 40; - public static boolean PrintDisabledOptimisticOptimizations = true; - public static int MatureExecutionsBranch = 1; - public static int MatureExecutionsPerSwitchCase = 1; - public static int MatureExecutionsTypeProfile = 1; - - // comilation queue - public static int TimedBootstrap = -1; - public static boolean PriorityCompileQueue = true; - public static int SlowQueueCutoff = 100000; - public static boolean SlowCompileThreads = ____; - public static boolean DynamicCompilePriority = ____; - - // graph caching - public static boolean CacheGraphs = true; - public static int GraphCacheSize = 1000; - public static boolean PrintGraphCache = ____; - - //rematerialize settings - public static float MinimumUsageProbability = 0.95f; - - //loop transform settings TODO (gd) tune - public static boolean LoopPeeling = true; - public static boolean ReassociateInvariants = true; - public static boolean FullUnroll = true; - public static boolean LoopUnswitch = true; - public static int FullUnrollMaxNodes = 150; - public static int ExactFullUnrollMaxNodes = 600; - public static float MinimumPeelProbability = 0.35f; - public static int LoopMaxUnswitch = 3; - public static int LoopUnswitchMaxIncrease = 50; - public static int LoopUnswitchUncertaintyBoost = 5; - - // debugging settings - public static int MethodEndBreakpointGuards = 0; - public static boolean ZapStackOnMethodEntry = ____; - public static boolean DeoptALot = ____; - public static boolean VerifyPhases = true; - public static boolean CreateDeoptInfo = ____; - - public static String PrintFilter = null; - - // printing settings - public static boolean PrintLIR = ____; - public static boolean PrintCFGToFile = ____; - - // Debug settings: - public static boolean Debug = true; - public static boolean PerThreadDebugValues = ____; - public static boolean SummarizeDebugValues = ____; - public static boolean SummarizePerPhase = ____; - public static String Dump = null; - public static String Meter = null; - public static String Time = null; - public static String Log = null; - public static String LogFile = null; - public static String MethodFilter = null; - public static boolean DumpOnError = ____; - - // Ideal graph visualizer output settings - public static boolean PrintBinaryGraphs = ____; - public static boolean PrintCFG = true; - public static boolean PrintIdealGraphFile = ____; - public static String PrintIdealGraphAddress = "127.0.0.1"; - public static int PrintIdealGraphPort = 4444; - public static int PrintBinaryGraphPort = 4445; - - // Other printing settings - public static boolean PrintQueue = ____; - public static boolean PrintCompilation = ____; - public static boolean PrintProfilingInformation = ____; - public static boolean PrintXirTemplates = ____; - public static boolean PrintIRWithLIR = ____; - public static boolean PrintAssembly = ____; - public static boolean PrintCodeBytes = ____; - public static int PrintAssemblyBytesPerLine = 16; - public static boolean PrintBailout = ____; - public static int TraceLinearScanLevel = 0; - public static boolean TraceRegisterAllocation = false; - public static int TraceLIRGeneratorLevel = 0; - public static boolean TraceEscapeAnalysis = ____; - public static int TraceBytecodeParserLevel = 0; - public static boolean PrintBailouts = true; - public static boolean ExitVMOnBailout = ____; - public static boolean ExitVMOnException = true; - - // state merging settings - public static boolean AssumeVerifiedBytecode = true; - - // Code generator settings - public static boolean CheckCastElimination = true; - public static boolean CullFrameStates = ____; - public static boolean UseProfilingInformation = true; - static boolean RemoveNeverExecutedCode = true; - static boolean UseExceptionProbability = true; - public static boolean AllowExplicitExceptionChecks = true; - public static boolean OmitHotExceptionStacktrace = ____; - public static boolean GenSafepoints = true; - public static boolean GenLoopSafepoints = true; - static boolean UseTypeCheckHints = true; - public static boolean InlineVTableStubs = true; - public static boolean AlwaysInlineVTableStubs = ____; - - public static boolean GenAssertionCode = ____; - public static boolean AlignCallsForPatching = true; - public static boolean ResolveClassBeforeStaticInvoke = true; - - // Translating tableswitch instructions - public static int SequentialSwitchLimit = 4; - public static int RangeTestsSwitchDensity = 5; - public static double MinTableSwitchDensity = 0.5; - - public static boolean DetailedAsserts = ____; - - // Runtime settings - public static int ReadPrefetchInstr = 0; - public static int StackShadowPages = 2; - - // Assembler settings - public static boolean CommentedAssembly = ____; - public static boolean PrintLIRWithAssembly = ____; - - public static boolean SupportJsrBytecodes = true; - - public static boolean OptAssumptions = true; - public static boolean OptReadElimination = true; - public static boolean OptGVN = true; - public static boolean OptCanonicalizer = true; - public static boolean ScheduleOutOfLoops = true; - public static boolean OptReorderLoops = true; - public static boolean OptEliminateGuards = true; - public static boolean OptImplicitNullChecks = true; - public static boolean OptLivenessAnalysis = true; - public static boolean OptLoopTransform = true; - public static boolean OptSafepointElimination = true; - public static boolean FloatingReads = true; - public static boolean OptTailDuplication = true; - - /** - * Prints all the available GraalOptions. - */ - public static boolean PrintFlags = false; - - /** - * Counts the various paths taken through snippets. - */ - public static boolean SnippetCounters = false; - - /** - * If the probability that a checkcast will hit one the profiled types (up to {@link #CheckcastMaxHints}) - * is below this value, the checkcast will be compiled without hints. - */ - public static double CheckcastMinHintHitProbability = 0.5; - - /** - * The maximum number of hint types that will be used when compiling a checkcast for which - * profiling information is available. Note that {@link #CheckcastMinHintHitProbability} - * also influences whether hints are used. - */ - public static int CheckcastMaxHints = 2; - - /** - * @see #CheckcastMinHintHitProbability - */ - public static double InstanceOfMinHintHitProbability = 0.5; - - /** - * @see #CheckcastMaxHints - */ - public static int InstanceOfMaxHints = 1; - - static { - // turn detailed assertions on when the general assertions are on (misusing the assert keyword for this) - assert (DetailedAsserts = true) == true; - assert (CommentedAssembly = true) == true; - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/OptimisticOptimizations.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; - - - -public final class OptimisticOptimizations { - public static final OptimisticOptimizations ALL = new OptimisticOptimizations(EnumSet.allOf(Optimization.class)); - public static final OptimisticOptimizations NONE = new OptimisticOptimizations(EnumSet.noneOf(Optimization.class)); - private static final DebugMetric disabledOptimisticOptsMetric = Debug.metric("DisabledOptimisticOpts"); - - private static enum Optimization { - RemoveNeverExecutedCode, - UseTypeCheckedInlining, - UseTypeCheckHints, - UseExceptionProbability - } - - private final Set<Optimization> enabledOpts; - - public OptimisticOptimizations(ResolvedJavaMethod method) { - this.enabledOpts = EnumSet.noneOf(Optimization.class); - - ProfilingInfo profilingInfo = method.profilingInfo(); - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.UnreachedCode)) { - enabledOpts.add(Optimization.RemoveNeverExecutedCode); - } - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.TypeCheckedInliningViolated)) { - enabledOpts.add(Optimization.UseTypeCheckedInlining); - } - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.OptimizedTypeCheckViolated)) { - enabledOpts.add(Optimization.UseTypeCheckHints); - } - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.NotCompiledExceptionHandler)) { - enabledOpts.add(Optimization.UseExceptionProbability); - } - } - - private OptimisticOptimizations(Set<Optimization> enabledOpts) { - this.enabledOpts = enabledOpts; - } - - public void log(JavaMethod method) { - for (Optimization opt: Optimization.values()) { - if (!enabledOpts.contains(opt)) { - if (GraalOptions.PrintDisabledOptimisticOptimizations) { - TTY.println("WARN: deactivated optimistic optimization %s for %s", opt.name(), MetaUtil.format("%H.%n(%p)", method)); - } - disabledOptimisticOptsMetric.increment(); - } - } - } - - public boolean removeNeverExecutedCode() { - return GraalOptions.RemoveNeverExecutedCode && enabledOpts.contains(Optimization.RemoveNeverExecutedCode); - } - - public boolean useTypeCheckHints() { - return GraalOptions.UseTypeCheckHints && enabledOpts.contains(Optimization.UseTypeCheckHints); - } - - public boolean inlineMonomorphicCalls() { - return GraalOptions.InlineMonomorphicCalls && enabledOpts.contains(Optimization.UseTypeCheckedInlining); - } - - public boolean inlinePolymorphicCalls() { - return GraalOptions.InlinePolymorphicCalls && enabledOpts.contains(Optimization.UseTypeCheckedInlining); - } - - public boolean inlineMegamorphicCalls() { - return GraalOptions.InlineMegamorphicCalls && enabledOpts.contains(Optimization.UseTypeCheckedInlining); - } - - public boolean useExceptionProbability() { - return GraalOptions.UseExceptionProbability && enabledOpts.contains(Optimization.UseExceptionProbability); - } - - public boolean lessOptimisticThan(OptimisticOptimizations other) { - for (Optimization opt: Optimization.values()) { - if (!enabledOpts.contains(opt) && other.enabledOpts.contains(opt)) { - return true; - } - } - return false; - } - - private static boolean checkDeoptimizations(ProfilingInfo profilingInfo, DeoptimizationReason reason) { - return profilingInfo.getDeoptimizationCount(reason) < GraalOptions.DeoptsToDisableOptimisticOptimization; - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/MergeableState.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.graph; - -import java.util.*; - -import com.oracle.graal.nodes.*; - -public interface MergeableState <T> { - T clone(); - boolean merge(MergeNode merge, List<T> withStates); - void loopBegin(LoopBeginNode loopBegin); - void loopEnds(LoopBeginNode loopBegin, List<T> loopEndStates); - void afterSplit(FixedNode node); -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.graph; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -/** - * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a specified fixed node.<br> - * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode}, {@link MergeNode}...) and the {@link FixedWithNextNode#next() next} pointers - * of {@link FixedWithNextNode}.<br> - * While iterating it maintains a user-defined state by calling the methods available in {@link MergeableState}. - * - * @param <T> the type of {@link MergeableState} handled by this PostOrderNodeIterator - */ -public abstract class PostOrderNodeIterator<T extends MergeableState<T>> { - - private final NodeBitMap visitedEnds; - private final Deque<FixedNode> nodeQueue; - private final IdentityHashMap<FixedNode, T> nodeStates; - private final FixedNode start; - - protected T state; - - public PostOrderNodeIterator(FixedNode start, T initialState) { - visitedEnds = start.graph().createNodeBitMap(); - nodeQueue = new ArrayDeque<>(); - nodeStates = new IdentityHashMap<>(); - this.start = start; - this.state = initialState; - } - - public void apply() { - FixedNode current = start; - - do { - if (current instanceof InvokeWithExceptionNode) { - invoke((Invoke) current); - queueSuccessors(current, null); - current = nextQueuedNode(); - } else if (current instanceof LoopBeginNode) { - state.loopBegin((LoopBeginNode) current); - nodeStates.put(current, state); - state = state.clone(); - loopBegin((LoopBeginNode) current); - current = ((LoopBeginNode) current).next(); - assert current != null; - } else if (current instanceof LoopEndNode) { - loopEnd((LoopEndNode) current); - finishLoopEnds((LoopEndNode) current); - current = nextQueuedNode(); - } else if (current instanceof MergeNode) { - merge((MergeNode) current); - current = ((MergeNode) current).next(); - assert current != null; - } else if (current instanceof FixedWithNextNode) { - FixedNode next = ((FixedWithNextNode) current).next(); - assert next != null : current; - node(current); - current = next; - } else if (current instanceof EndNode) { - end((EndNode) current); - queueMerge((EndNode) current); - current = nextQueuedNode(); - } else if (current instanceof DeoptimizeNode) { - deoptimize((DeoptimizeNode) current); - current = nextQueuedNode(); - } else if (current instanceof ReturnNode) { - returnNode((ReturnNode) current); - current = nextQueuedNode(); - } else if (current instanceof UnwindNode) { - unwind((UnwindNode) current); - current = nextQueuedNode(); - } else if (current instanceof ControlSplitNode) { - Set<Node> successors = controlSplit((ControlSplitNode) current); - queueSuccessors(current, successors); - current = nextQueuedNode(); - } else { - assert false : current; - } - } while(current != null); - } - - private void queueSuccessors(FixedNode x, Set<Node> successors) { - nodeStates.put(x, state); - if (successors != null) { - for (Node node : successors) { - if (node != null) { - nodeStates.put((FixedNode) node.predecessor(), state); - nodeQueue.addFirst((FixedNode) node); - } - } - } else { - for (Node node : x.successors()) { - if (node != null) { - nodeQueue.addFirst((FixedNode) node); - } - } - } - } - - private FixedNode nextQueuedNode() { - int maxIterations = nodeQueue.size(); - while (maxIterations-- > 0) { - FixedNode node = nodeQueue.removeFirst(); - if (node instanceof MergeNode) { - MergeNode merge = (MergeNode) node; - state = nodeStates.get(merge.forwardEndAt(0)).clone(); - ArrayList<T> states = new ArrayList<>(merge.forwardEndCount() - 1); - for (int i = 1; i < merge.forwardEndCount(); i++) { - T other = nodeStates.get(merge.forwardEndAt(i)); - assert other != null; - states.add(other); - } - boolean ready = state.merge(merge, states); - if (ready) { - return merge; - } else { - nodeQueue.addLast(merge); - } - } else { - assert node.predecessor() != null; - state = nodeStates.get(node.predecessor()).clone(); - state.afterSplit(node); - return node; - } - } - return null; - } - - private void finishLoopEnds(LoopEndNode end) { - assert !visitedEnds.isMarked(end); - assert !nodeStates.containsKey(end); - nodeStates.put(end, state); - visitedEnds.mark(end); - LoopBeginNode begin = end.loopBegin(); - boolean endsVisited = true; - for (LoopEndNode le : begin.loopEnds()) { - if (!visitedEnds.isMarked(le)) { - endsVisited = false; - break; - } - } - if (endsVisited) { - ArrayList<T> states = new ArrayList<>(begin.loopEnds().count()); - for (LoopEndNode le : begin.orderedLoopEnds()) { - states.add(nodeStates.get(le)); - } - T loopBeginState = nodeStates.get(begin); - if (loopBeginState != null) { - loopBeginState.loopEnds(begin, states); - } - } - } - - private void queueMerge(EndNode end) { - assert !visitedEnds.isMarked(end); - assert !nodeStates.containsKey(end); - nodeStates.put(end, state); - visitedEnds.mark(end); - MergeNode merge = end.merge(); - boolean endsVisited = true; - for (int i = 0; i < merge.forwardEndCount(); i++) { - if (!visitedEnds.isMarked(merge.forwardEndAt(i))) { - endsVisited = false; - break; - } - } - if (endsVisited) { - nodeQueue.add(merge); - } - } - - protected abstract void node(FixedNode node); - - protected void end(EndNode endNode) { - node(endNode); - } - - protected void merge(MergeNode merge) { - node(merge); - } - - protected void loopBegin(LoopBeginNode loopBegin) { - node(loopBegin); - } - - protected void loopEnd(LoopEndNode loopEnd) { - node(loopEnd); - } - - protected void deoptimize(DeoptimizeNode deoptimize) { - node(deoptimize); - } - - protected Set<Node> controlSplit(ControlSplitNode controlSplit) { - node(controlSplit); - return null; - } - - protected void returnNode(ReturnNode returnNode) { - node(returnNode); - } - - protected void invoke(Invoke invoke) { - node(invoke.node()); - } - - protected void unwind(UnwindNode unwind) { - node(unwind); - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/package-info.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * - */ -package com.oracle.graal.compiler.graph;
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/package-info.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * The top-level package in Graal containing options, metrics and timers. - * - * Graal is intended to be used with multiple JVM's so makes no use of or reference to classes for a specific JVM. - */ -package com.oracle.graal.compiler;
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import static com.oracle.graal.graph.iterators.NodePredicates.*; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; - -public class BoxingEliminationPhase extends Phase { - - private int virtualIds = Integer.MIN_VALUE; - - @Override - protected void run(StructuredGraph graph) { - if (graph.getNodes(UnboxNode.class).isNotEmpty()) { - - Map<PhiNode, PhiNode> phiReplacements = new HashMap<>(); - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - tryEliminate(graph, unboxNode, phiReplacements); - } - - new DeadCodeEliminationPhase().apply(graph); - - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - tryEliminate(boxNode); - } - } - } - - private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map<PhiNode, PhiNode> phiReplacements) { - ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == unboxNode.kind(); - unboxNode.replaceAtUsages(unboxedValue); - graph.removeFixed(unboxNode); - } - } - - private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map<PhiNode, PhiNode> phiReplacements) { - if (!phiReplacements.containsKey(phiNode)) { - PhiNode result = null; - ObjectStamp stamp = phiNode.objectStamp(); - if (stamp.nonNull() && stamp.isExactType()) { - ResolvedJavaType type = stamp.type(); - if (type != null && type.toJava() == kind.toBoxedJavaClass()) { - StructuredGraph graph = (StructuredGraph) phiNode.graph(); - result = graph.add(new PhiNode(kind, phiNode.merge())); - phiReplacements.put(phiNode, result); - virtualizeUsages(phiNode, result, type); - int i = 0; - for (ValueNode n : phiNode.values()) { - ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == kind; - result.addInput(unboxedValue); - } else { - UnboxNode unboxNode = graph.add(new UnboxNode(kind, n)); - FixedNode pred = phiNode.merge().phiPredecessorAt(i); - graph.addBeforeFixed(pred, unboxNode); - result.addInput(unboxNode); - } - ++i; - } - } - } - } - return phiReplacements.get(phiNode); - } - - private ValueNode unboxedValue(ValueNode n, Kind kind, Map<PhiNode, PhiNode> phiReplacements) { - if (n instanceof BoxNode) { - BoxNode boxNode = (BoxNode) n; - return boxNode.source(); - } else if (n instanceof PhiNode) { - PhiNode phiNode = (PhiNode) n; - return getReplacementPhi(phiNode, kind, phiReplacements); - } else { - return null; - } - } - - private void tryEliminate(BoxNode boxNode) { - - assert boxNode.objectStamp().isExactType(); - virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type()); - - if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) { - // Elimination failed, because boxing object escapes. - return; - } - - FrameState stateAfter = boxNode.stateAfter(); - boxNode.setStateAfter(null); - stateAfter.safeDelete(); - - ((StructuredGraph) boxNode.graph()).removeFixed(boxNode); - } - - private void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) { - ValueNode virtualValueNode = null; - VirtualObjectNode virtualObjectNode = null; - for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) { - if (virtualValueNode == null) { - virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(virtualIds++, exactType, replacement)); - } - n.replaceFirstInput(boxNode, virtualObjectNode); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,331 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Graph.InputChangedListener; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -public class CanonicalizerPhase extends Phase { - private static final int MAX_ITERATION_PER_NODE = 10; - private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes"); - private static final DebugMetric METRIC_CANONICALIZATION_CONSIDERED_NODES = Debug.metric("CanonicalizationConsideredNodes"); - private static final DebugMetric METRIC_INFER_STAMP_CALLED = Debug.metric("InferStampCalled"); - private static final DebugMetric METRIC_STAMP_CHANGED = Debug.metric("StampChanged"); - private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes"); - public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits"); - - private final int newNodesMark; - private final TargetDescription target; - private final Assumptions assumptions; - private final MetaAccessProvider runtime; - private final IsImmutablePredicate immutabilityPredicate; - private final Iterable<Node> initWorkingSet; - - private NodeWorkList workList; - private Tool tool; - private List<Node> snapshotTemp; - - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { - this(target, runtime, assumptions, null, 0, null); - } - - /** - * @param target - * @param runtime - * @param assumptions - * @param workingSet the initial working set of nodes on which the canonicalizer works, should be an auto-grow node bitmap - * @param immutabilityPredicate - */ - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, IsImmutablePredicate immutabilityPredicate) { - this(target, runtime, assumptions, workingSet, 0, immutabilityPredicate); - } - - /** - * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by - * this mark are processed otherwise all nodes in the graph are processed - */ - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, IsImmutablePredicate immutabilityPredicate) { - this(target, runtime, assumptions, null, newNodesMark, immutabilityPredicate); - } - - private CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, int newNodesMark, IsImmutablePredicate immutabilityPredicate) { - this.newNodesMark = newNodesMark; - this.target = target; - this.assumptions = assumptions; - this.runtime = runtime; - this.immutabilityPredicate = immutabilityPredicate; - this.initWorkingSet = workingSet; - this.snapshotTemp = new ArrayList<>(); - } - - @Override - protected void run(StructuredGraph graph) { - if (initWorkingSet == null) { - workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE); - if (newNodesMark > 0) { - workList.addAll(graph.getNewNodes(newNodesMark)); - } - } else { - workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE); - workList.addAll(initWorkingSet); - } - tool = new Tool(workList, runtime, target, assumptions, immutabilityPredicate); - processWorkSet(graph); - } - - public interface IsImmutablePredicate { - /** - * Determines if a given constant is an object/array whose current - * fields/elements will never change. - */ - boolean apply(Constant constant); - } - - private void processWorkSet(StructuredGraph graph) { - graph.trackInputChange(new InputChangedListener() { - @Override - public void inputChanged(Node node) { - workList.addAgain(node); - } - }); - - for (Node n : workList) { - processNode(n, graph); - } - - graph.stopTrackingInputChange(); - } - - private void processNode(Node node, StructuredGraph graph) { - if (node.isAlive()) { - METRIC_PROCESSED_NODES.increment(); - - if (tryGlobalValueNumbering(node, graph)) { - return; - } - int mark = graph.getMark(); - if (!tryKillUnused(node)) { - node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); - if (!tryCanonicalize(node, graph, tool)) { - tryInferStamp(node, graph); - } else { - for (Node in : snapshotTemp) { - if (in.isAlive() && in.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(in); - } - } - } - snapshotTemp.clear(); - } - - for (Node newNode : graph.getNewNodes(mark)) { - workList.add(newNode); - } - } - } - - private static boolean tryKillUnused(Node node) { - if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(node); - return true; - } - return false; - } - - public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) { - if (node.getNodeClass().valueNumberable()) { - Node newNode = graph.findDuplicate(node); - if (newNode != null) { - assert !(node instanceof FixedNode || newNode instanceof FixedNode); - node.replaceAtUsages(newNode); - node.safeDelete(); - METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment(); - Debug.log("GVN applied and new node is %1s", newNode); - return true; - } - } - return false; - } - - public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) { - if (node instanceof Canonicalizable) { - assert !(node instanceof Simplifiable); - METRIC_CANONICALIZATION_CONSIDERED_NODES.increment(); - return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>(){ - public Boolean call() { - ValueNode canonical = ((Canonicalizable) node).canonical(tool); -// cases: original node: -// |Floating|Fixed-unconnected|Fixed-connected| -// -------------------------------------------- -// null| 1 | X | 3 | -// -------------------------------------------- -// Floating| 2 | X | 4 | -// canonical node: -------------------------------------------- -// Fixed-unconnected| X | X | 5 | -// -------------------------------------------- -// Fixed-connected| 2 | X | 6 | -// -------------------------------------------- -// X: must not happen (checked with assertions) - if (canonical == node) { - Debug.log("Canonicalizer: work on %s", node); - return false; - } else { - Debug.log("Canonicalizer: replacing %s with %s", node, canonical); - METRIC_CANONICALIZED_NODES.increment(); - if (node instanceof FloatingNode) { - if (canonical == null) { - // case 1 - graph.removeFloating((FloatingNode) node); - } else { - // case 2 - assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode) : node + " -> " + canonical + - " : replacement should be floating or fixed and connected"; - graph.replaceFloating((FloatingNode) node, canonical); - } - } else { - assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")"; - if (canonical == null) { - // case 3 - graph.removeFixed((FixedWithNextNode) node); - } else if (canonical instanceof FloatingNode) { - // case 4 - graph.replaceFixedWithFloating((FixedWithNextNode) node, (FloatingNode) canonical); - } else { - assert canonical instanceof FixedNode; - if (canonical.predecessor() == null) { - assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors"; - // case 5 - graph.replaceFixedWithFixed((FixedWithNextNode) node, (FixedWithNextNode) canonical); - } else { - assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors"; - // case 6 - node.replaceAtUsages(canonical); - graph.removeFixed((FixedWithNextNode) node); - } - } - } - return true; - } - } - }); - } else if (node instanceof Simplifiable) { - Debug.log("Canonicalizer: simplifying %s", node); - METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment(); - Debug.scope("SimplifyNode", node, new Runnable() { - public void run() { - ((Simplifiable) node).simplify(tool); - } - }); - } - return node.isDeleted(); - } - - /** - * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that the stamp has - * changed), re-queues the node's usages . If the stamp has changed then this method also checks if the stamp - * now describes a constant integer value, in which case the node is replaced with a constant. - */ - private void tryInferStamp(Node node, StructuredGraph graph) { - if (node.isAlive() && node instanceof ValueNode) { - ValueNode valueNode = (ValueNode) node; - METRIC_INFER_STAMP_CALLED.increment(); - if (valueNode.inferStamp()) { - METRIC_STAMP_CHANGED.increment(); - if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) { - ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph); - Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement); - valueNode.replaceAtUsages(replacement); - } else { - for (Node usage : valueNode.usages()) { - workList.addAgain(usage); - } - } - } - } - } - - private static final class Tool implements SimplifierTool { - - private final NodeWorkList nodeWorkSet; - private final MetaAccessProvider runtime; - private final TargetDescription target; - private final Assumptions assumptions; - private final IsImmutablePredicate immutabilityPredicate; - - public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, TargetDescription target, Assumptions assumptions, IsImmutablePredicate immutabilityPredicate) { - this.nodeWorkSet = nodeWorkSet; - this.runtime = runtime; - this.target = target; - this.assumptions = assumptions; - this.immutabilityPredicate = immutabilityPredicate; - } - - @Override - public void deleteBranch(FixedNode branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch); - } - - /** - * @return the current target or {@code null} if no target is available in the current context. - */ - @Override - public TargetDescription target() { - return target; - } - - /** - * @return an object that can be used for recording assumptions or {@code null} if assumptions are not allowed in the current context. - */ - @Override - public Assumptions assumptions() { - return assumptions; - } - - @Override - public MetaAccessProvider runtime() { - return runtime; - } - - @Override - public void addToWorkList(Node node) { - nodeWorkSet.add(node); - } - - @Override - public boolean isImmutable(Constant objectConstant) { - return immutabilityPredicate != null && immutabilityPredicate.apply(objectConstant); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,383 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -public class CheckCastEliminationPhase extends Phase { - - private static final DebugMetric metricInstanceOfRegistered = Debug.metric("InstanceOfRegistered"); - private static final DebugMetric metricNullCheckRegistered = Debug.metric("NullCheckRegistered"); - private static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved"); - private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved"); - private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved"); - private static final DebugMetric metricNullCheckGuardRemoved = Debug.metric("NullCheckGuardRemoved"); - private static final DebugMetric metricGuardsReplaced = Debug.metric("GuardsReplaced"); - - private StructuredGraph graph; - - @Override - protected void run(StructuredGraph inputGraph) { - graph = inputGraph; - new EliminateCheckCasts(graph.start(), new State()).apply(); - } - - public static class State implements MergeableState<State> { - - private IdentityHashMap<ValueNode, ResolvedJavaType> knownTypes; - private HashSet<ValueNode> knownNotNull; - private HashSet<ValueNode> knownNull; - private IdentityHashMap<BooleanNode, ValueNode> trueConditions; - private IdentityHashMap<BooleanNode, ValueNode> falseConditions; - - public State() { - this.knownTypes = new IdentityHashMap<>(); - this.knownNotNull = new HashSet<>(); - this.knownNull = new HashSet<>(); - this.trueConditions = new IdentityHashMap<>(); - this.falseConditions = new IdentityHashMap<>(); - } - - public State(State other) { - this.knownTypes = new IdentityHashMap<>(other.knownTypes); - this.knownNotNull = new HashSet<>(other.knownNotNull); - this.knownNull = new HashSet<>(other.knownNull); - this.trueConditions = new IdentityHashMap<>(other.trueConditions); - this.falseConditions = new IdentityHashMap<>(other.falseConditions); - } - - @Override - public boolean merge(MergeNode merge, List<State> withStates) { - IdentityHashMap<ValueNode, ResolvedJavaType> newKnownTypes = new IdentityHashMap<>(); - HashSet<ValueNode> newKnownNotNull = new HashSet<>(); - HashSet<ValueNode> newKnownNull = new HashSet<>(); - IdentityHashMap<BooleanNode, ValueNode> newTrueConditions = new IdentityHashMap<>(); - IdentityHashMap<BooleanNode, ValueNode> newFalseConditions = new IdentityHashMap<>(); - - for (Map.Entry<ValueNode, ResolvedJavaType> entry : knownTypes.entrySet()) { - ValueNode node = entry.getKey(); - ResolvedJavaType type = entry.getValue(); - - for (State other : withStates) { - ResolvedJavaType otherType = other.getNodeType(node); - type = widen(type, otherType); - if (type == null) { - break; - } - } - if (type == null && type != node.objectStamp().type()) { - newKnownTypes.put(node, type); - } - } - for (ValueNode node : knownNotNull) { - boolean notNull = true; - for (State other : withStates) { - if (!other.knownNotNull.contains(node)) { - notNull = false; - break; - } - } - if (notNull) { - newKnownNotNull.add(node); - } - } - for (ValueNode node : knownNull) { - boolean nul = true; - for (State other : withStates) { - if (!other.knownNull.contains(node)) { - nul = false; - break; - } - } - if (nul) { - newKnownNull.add(node); - } - } - for (Map.Entry<BooleanNode, ValueNode> entry : trueConditions.entrySet()) { - BooleanNode check = entry.getKey(); - ValueNode guard = entry.getValue(); - - for (State other : withStates) { - ValueNode otherGuard = other.trueConditions.get(check); - if (otherGuard == null) { - guard = null; - break; - } - if (otherGuard != guard) { - guard = merge; - } - } - if (guard != null) { - newTrueConditions.put(check, guard); - } - } - for (Map.Entry<BooleanNode, ValueNode> entry : falseConditions.entrySet()) { - BooleanNode check = entry.getKey(); - ValueNode guard = entry.getValue(); - - for (State other : withStates) { - ValueNode otherGuard = other.falseConditions.get(check); - if (otherGuard == null) { - guard = null; - break; - } - if (otherGuard != guard) { - guard = merge; - } - } - if (guard != null) { - newFalseConditions.put(check, guard); - } - } - - /* - // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values) - if (!(merge instanceof LoopBeginNode)) { - for (PhiNode phi : merge.phis()) { - if (phi.type() == PhiType.Value && phi.kind() == Kind.Object) { - ValueNode firstValue = phi.valueAt(0); - ResolvedJavaType type = getNodeType(firstValue); - boolean notNull = knownNotNull.contains(firstValue); - boolean nul = knownNull.contains(firstValue); - - for (int i = 0; i < withStates.size(); i++) { - State otherState = withStates.get(i); - ValueNode value = phi.valueAt(i + 1); - ResolvedJavaType otherType = otherState.getNodeType(value); - type = widen(type, otherType); - notNull &= otherState.knownNotNull.contains(value); - nul &= otherState.knownNull.contains(value); - } - if (type == null && type != phi.declaredType()) { - newKnownTypes.put(phi, type); - } - if (notNull) { - newKnownNotNull.add(phi); - } - if (nul) { - newKnownNull.add(phi); - } - } - } - } - */ - this.knownTypes = newKnownTypes; - this.knownNotNull = newKnownNotNull; - this.knownNull = newKnownNull; - this.trueConditions = newTrueConditions; - this.falseConditions = newFalseConditions; - return true; - } - - public ResolvedJavaType getNodeType(ValueNode node) { - ResolvedJavaType result = knownTypes.get(node); - return result == null ? node.objectStamp().type() : result; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) { - } - - @Override - public void afterSplit(FixedNode node) { - } - - @Override - public State clone() { - return new State(this); - } - } - - public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) { - if (a == null || b == null) { - return null; - } else if (a == b) { - return a; - } else { - return a.leastCommonAncestor(b); - } - } - - public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) { - if (a == null) { - return b; - } else if (b == null) { - return a; - } else if (a == b) { - return a; - } else if (a.isSubtypeOf(b)) { - return a; - } else if (b.isSubtypeOf(a)) { - return b; - } else { - return a; - } - } - - public class EliminateCheckCasts extends PostOrderNodeIterator<State> { - private BeginNode lastBegin = null; - - public EliminateCheckCasts(FixedNode start, State initialState) { - super(start, initialState); - } - - @Override - protected void node(FixedNode node) { - if (node instanceof BeginNode) { - BeginNode begin = (BeginNode) node; - lastBegin = begin; - Node pred = node.predecessor(); - if (pred != null && pred instanceof IfNode) { - IfNode ifNode = (IfNode) pred; - if (!(ifNode.compare() instanceof ConstantNode)) { - boolean isTrue = (node == ifNode.trueSuccessor()); - if (isTrue) { - state.trueConditions.put(ifNode.compare(), begin); - } else { - state.falseConditions.put(ifNode.compare(), begin); - } - } - if (ifNode.compare() instanceof InstanceOfNode) { - InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare(); - if ((node == ifNode.trueSuccessor())) { - ValueNode object = instanceOf.object(); - state.knownNotNull.add(object); - state.knownTypes.put(object, tighten(instanceOf.targetClass(), state.getNodeType(object))); - metricInstanceOfRegistered.increment(); - } - } else if (ifNode.compare() instanceof IsNullNode) { - IsNullNode nullCheck = (IsNullNode) ifNode.compare(); - boolean isNull = (node == ifNode.trueSuccessor()); - if (isNull) { - state.knownNull.add(nullCheck.object()); - } else { - state.knownNotNull.add(nullCheck.object()); - } - metricNullCheckRegistered.increment(); - } - } - for (GuardNode guard : begin.guards().snapshot()) { - BooleanNode condition = guard.condition(); - ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition); - if (existingGuards != null) { - guard.replaceAtUsages(existingGuards); - GraphUtil.killWithUnusedFloatingInputs(guard); - metricGuardsReplaced.increment(); - } else { - boolean removeCheck = false; - if (condition instanceof IsNullNode) { - IsNullNode isNull = (IsNullNode) condition; - if (guard.negated() && state.knownNotNull.contains(isNull.object())) { - removeCheck = true; - } else if (!guard.negated() && state.knownNull.contains(isNull.object())) { - removeCheck = true; - } - if (removeCheck) { - metricNullCheckGuardRemoved.increment(); - } - } - if (removeCheck) { - guard.replaceAtUsages(begin); - GraphUtil.killWithUnusedFloatingInputs(guard); - } else { - if (guard.negated()) { - state.falseConditions.put(condition, guard); - } else { - state.trueConditions.put(condition, guard); - } - } - } - } - } else if (node instanceof CheckCastNode) { - CheckCastNode checkCast = (CheckCastNode) node; - ResolvedJavaType type = state.getNodeType(checkCast.object()); - if (checkCast.targetClass() != null && type != null && type.isSubtypeOf(checkCast.targetClass())) { - PiNode piNode; - boolean nonNull = state.knownNotNull.contains(checkCast.object()); - piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, nonNull ? StampFactory.declaredNonNull(type) : StampFactory.declared(type))); - checkCast.replaceAtUsages(piNode); - graph.removeFixed(checkCast); - metricCheckCastRemoved.increment(); - } - } else if (node instanceof IfNode) { - IfNode ifNode = (IfNode) node; - BooleanNode replaceWith = null; - BooleanNode compare = ifNode.compare(); - - if (state.trueConditions.containsKey(compare)) { - replaceWith = ConstantNode.forBoolean(true, graph); - } else if (state.falseConditions.containsKey(compare)) { - replaceWith = ConstantNode.forBoolean(false, graph); - } else { - if (compare instanceof InstanceOfNode) { - InstanceOfNode instanceOf = (InstanceOfNode) compare; - ValueNode object = instanceOf.object(); - if (state.knownNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(false, graph); - } else if (state.knownNotNull.contains(object)) { - ResolvedJavaType type = state.getNodeType(object); - if (type != null && type.isSubtypeOf(instanceOf.targetClass())) { - replaceWith = ConstantNode.forBoolean(true, graph); - } - } - if (replaceWith != null) { - metricInstanceOfRemoved.increment(); - } - } else if (compare instanceof IsNullNode) { - IsNullNode isNull = (IsNullNode) compare; - ValueNode object = isNull.object(); - if (state.knownNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(true, graph); - } else if (state.knownNotNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(false, graph); - } - if (replaceWith != null) { - metricNullCheckRemoved.increment(); - } - } - } - if (replaceWith != null) { - ifNode.setCompare(replaceWith); - if (compare.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(compare); - } - } - } - } - } - -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ComputeProbabilityPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,372 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - -public class ComputeProbabilityPhase extends Phase { - private static final double EPSILON = 1d / Integer.MAX_VALUE; - - /* - * The computation of absolute probabilities works in three steps: - * - * - The first step, "PropagateProbability", traverses the graph in post order (merges after their ends, ...) and keeps track of the "probability state". - * Whenever it encounters a ControlSplit it uses the split's probability information to divide the probability upon the successors. - * Whenever it encounters an Invoke it assumes that the exception edge is unlikely and propagates the whole probability to the normal successor. - * Whenever it encounters a Merge it sums up the probability of all predecessors. - * It also maintains a set of active loops (whose LoopBegin has been visited) and builds def/use information for the second step. - * - * - The third step propagates the loop frequencies and multiplies each FixedNode's probability with its loop frequency. - * - * TODO: add exception probability information to Invokes - */ - - @Override - protected void run(StructuredGraph graph) { - new PropagateProbability(graph.start()).apply(); - Debug.dump(graph, "After PropagateProbability"); - computeLoopFactors(); - Debug.dump(graph, "After computeLoopFactors"); - new PropagateLoopFrequency(graph.start()).apply(); - - if (GraalOptions.LoopFrequencyPropagationPolicy < 0) { - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); - BitSet visitedBlocks = new BitSet(cfg.getBlocks().length); - for (Loop loop : cfg.getLoops()) { - if (loop.parent == null) { - correctLoopFrequencies(loop, 1, visitedBlocks); - } - } - } - } - - private void correctLoopFrequencies(Loop loop, double parentFrequency, BitSet visitedBlocks) { - LoopBeginNode loopBegin = ((LoopBeginNode) loop.header.getBeginNode()); - double frequency = parentFrequency * loopBegin.loopFrequency(); - for (Loop child : loop.children) { - correctLoopFrequencies(child, frequency, visitedBlocks); - } - - double factor = getCorrectionFactor(loopBegin.probability(), frequency); - for (Block block : loop.blocks) { - int blockId = block.getId(); - if (!visitedBlocks.get(blockId)) { - visitedBlocks.set(blockId); - - FixedNode node = block.getBeginNode(); - while (node != block.getEndNode()) { - node.setProbability(node.probability() * factor); - node = ((FixedWithNextNode) node).next(); - } - node.setProbability(node.probability() * factor); - } - } - } - - private static double getCorrectionFactor(double probability, double frequency) { - switch (GraalOptions.LoopFrequencyPropagationPolicy) { - case -1: - return 1 / frequency; - case -2: - return (1 / frequency) * (Math.log(Math.E + frequency) - 1); - case -3: - double originalProbability = probability / frequency; - assert isRelativeProbability(originalProbability); - return (1 / frequency) * Math.max(1, Math.pow(originalProbability, 1.5) * Math.log10(frequency)); - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - private void computeLoopFactors() { - for (LoopInfo info : loopInfos) { - double frequency = info.loopFrequency(); - assert frequency != -1; - } - } - - private static boolean isRelativeProbability(double prob) { - // 1.01 to allow for some rounding errors - return prob >= 0 && prob <= 1.01; - } - - public static class LoopInfo { - public final LoopBeginNode loopBegin; - - public final NodeMap<Set<LoopInfo>> requires; - - private double loopFrequency = -1; - public boolean ended = false; - - public LoopInfo(LoopBeginNode loopBegin) { - this.loopBegin = loopBegin; - this.requires = loopBegin.graph().createNodeMap(); - } - - public double loopFrequency() { - if (loopFrequency == -1 && ended) { - double backEdgeProb = 0.0; - for (LoopEndNode le : loopBegin.loopEnds()) { - double factor = 1; - Set<LoopInfo> requireds = requires.get(le); - for (LoopInfo required : requireds) { - double t = required.loopFrequency(); - if (t == -1) { - return -1; - } - factor *= t; - } - backEdgeProb += le.probability() * factor; - } - double d = loopBegin.probability() - backEdgeProb; - if (d < EPSILON) { - d = EPSILON; - } - loopFrequency = loopBegin.probability() / d; - loopBegin.setLoopFrequency(loopFrequency); - } - return loopFrequency; - } - } - - public Set<LoopInfo> loopInfos = new HashSet<>(); - public Map<MergeNode, Set<LoopInfo>> mergeLoops = new IdentityHashMap<>(); - - private class Probability implements MergeableState<Probability> { - public double probability; - public HashSet<LoopInfo> loops; - public LoopInfo loopInfo; - - public Probability(double probability, HashSet<LoopInfo> loops) { - this.probability = probability; - this.loops = new HashSet<>(4); - if (loops != null) { - this.loops.addAll(loops); - } - } - - @Override - public Probability clone() { - return new Probability(probability, loops); - } - - @Override - public boolean merge(MergeNode merge, List<Probability> withStates) { - if (merge.forwardEndCount() > 1) { - HashSet<LoopInfo> intersection = new HashSet<>(loops); - for (Probability other : withStates) { - intersection.retainAll(other.loops); - } - for (LoopInfo info : loops) { - if (!intersection.contains(info)) { - double loopFrequency = info.loopFrequency(); - if (loopFrequency == -1) { - return false; - } - probability *= loopFrequency; - } - } - for (Probability other : withStates) { - double prob = other.probability; - for (LoopInfo info : other.loops) { - if (!intersection.contains(info)) { - double loopFrequency = info.loopFrequency(); - if (loopFrequency == -1) { - return false; - } - prob *= loopFrequency; - } - } - probability += prob; - } - loops = intersection; - mergeLoops.put(merge, new HashSet<>(intersection)); - assert isRelativeProbability(probability) : probability; - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - loopInfo = new LoopInfo(loopBegin); - loopInfos.add(loopInfo); - loops.add(loopInfo); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List<Probability> loopEndStates) { - assert loopInfo != null; - List<LoopEndNode> loopEnds = loopBegin.orderedLoopEnds(); - int i = 0; - for (Probability proba : loopEndStates) { - LoopEndNode loopEnd = loopEnds.get(i++); - Set<LoopInfo> requires = loopInfo.requires.get(loopEnd); - if (requires == null) { - requires = new HashSet<>(); - loopInfo.requires.set(loopEnd, requires); - } - for (LoopInfo innerLoop : proba.loops) { - if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) { - requires.add(innerLoop); - } - } - } - loopInfo.ended = true; - } - - @Override - public void afterSplit(FixedNode node) { - assert node.predecessor() != null; - Node pred = node.predecessor(); - if (pred instanceof Invoke) { - Invoke x = (Invoke) pred; - if (x.next() != node) { - probability = 0; - } - } else { - assert pred instanceof ControlSplitNode; - ControlSplitNode x = (ControlSplitNode) pred; - double sum = 0; - for (int i = 0; i < x.blockSuccessorCount(); i++) { - if (x.blockSuccessor(i) == node) { - sum += x.probability(i); - } - } - probability *= sum; - } - } - } - - private class PropagateProbability extends PostOrderNodeIterator<Probability> { - - public PropagateProbability(FixedNode start) { - super(start, new Probability(1d, null)); - } - - @Override - protected void node(FixedNode node) { - node.setProbability(state.probability); - } - } - - private class LoopCount implements MergeableState<LoopCount> { - public double count; - - public LoopCount(double count) { - this.count = count; - } - - @Override - public LoopCount clone() { - return new LoopCount(count); - } - - @Override - public boolean merge(MergeNode merge, List<LoopCount> withStates) { - assert merge.forwardEndCount() == withStates.size() + 1; - if (merge.forwardEndCount() > 1) { - Set<LoopInfo> loops = mergeLoops.get(merge); - assert loops != null; - double countProd = 1; - for (LoopInfo loop : loops) { - countProd *= loop.loopFrequency(); - } - count = countProd; - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - count *= loopBegin.loopFrequency(); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List<LoopCount> loopEndStates) { - // nothing to do... - } - - @Override - public void afterSplit(FixedNode node) { - // nothing to do... - } - } - - private class PropagateLoopFrequency extends PostOrderNodeIterator<LoopCount> { - - private final FrequencyPropagationPolicy policy; - - public PropagateLoopFrequency(FixedNode start) { - super(start, new LoopCount(1d)); - this.policy = createFrequencyPropagationPolicy(); - } - - @Override - protected void node(FixedNode node) { - node.setProbability(policy.compute(node.probability(), state.count)); - } - - } - - private static FrequencyPropagationPolicy createFrequencyPropagationPolicy() { - switch (GraalOptions.LoopFrequencyPropagationPolicy) { - case -3: - case -2: - case -1: - case 0: - return new FullFrequencyPropagation(); - case 1: - return new NoFrequencyPropagation(); - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - private interface FrequencyPropagationPolicy { - - double compute(double probability, double frequency); - } - - private static class FullFrequencyPropagation implements FrequencyPropagationPolicy { - - @Override - public double compute(double probability, double frequency) { - return probability * frequency; - } - } - - private static class NoFrequencyPropagation implements FrequencyPropagationPolicy { - - @Override - public double compute(double probability, double frequency) { - return probability; - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; - -public class ConvertDeoptimizeToGuardPhase extends Phase { - - private static BeginNode findBeginNode(Node startNode) { - Node n = startNode; - while (true) { - if (n instanceof BeginNode) { - return (BeginNode) n; - } else { - n = n.predecessor(); - } - } - } - - @Override - protected void run(final StructuredGraph graph) { - if (graph.getNodes(DeoptimizeNode.class).isEmpty()) { - return; - } - - for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) { - visitDeoptBegin(findBeginNode(d), d, graph); - } - - new DeadCodeEliminationPhase().apply(graph); - } - - private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) { - if (deoptBegin instanceof MergeNode) { - MergeNode mergeNode = (MergeNode) deoptBegin; - Debug.log("Visiting %s followed by %s", mergeNode, deopt); - List<EndNode> ends = mergeNode.forwardEnds().snapshot(); - for (EndNode end : ends) { - if (!end.isDeleted()) { - BeginNode beginNode = findBeginNode(end); - if (!(beginNode instanceof MergeNode)) { - visitDeoptBegin(beginNode, deopt, graph); - } - } - } - if (mergeNode.isDeleted()) { - if (!deopt.isDeleted()) { - Debug.log("Merge deleted, deopt moved to %s", findBeginNode(deopt)); - visitDeoptBegin(findBeginNode(deopt), deopt, graph); - } - } - } else if (deoptBegin.predecessor() instanceof IfNode) { - IfNode ifNode = (IfNode) deoptBegin.predecessor(); - BeginNode otherBegin = ifNode.trueSuccessor(); - BooleanNode conditionNode = ifNode.compare(); - boolean negated = false; - if (deoptBegin == ifNode.trueSuccessor()) { - negated = true; - otherBegin = ifNode.falseSuccessor(); - } - BeginNode ifBlockBegin = findBeginNode(ifNode); - Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, ifBlockBegin); - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), negated, deopt.leafGraphId())); - otherBegin.replaceAtUsages(ifBlockBegin); - FixedNode next = otherBegin.next(); - otherBegin.setNext(null); - guard.setNext(next); - ifNode.replaceAtPredecessor(guard); - GraphUtil.killCFG(ifNode); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertUnreachedToGuardPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.util.*; - - -public class ConvertUnreachedToGuardPhase extends Phase { - private OptimisticOptimizations opt; - - public ConvertUnreachedToGuardPhase(OptimisticOptimizations opt) { - this.opt = opt; - } - - @Override - protected void run(StructuredGraph graph) { - if (!opt.removeNeverExecutedCode()) { - return; - } - for (Node node : graph.getNodes()) { - if (node instanceof IfNode) { - IfNode ifNode = (IfNode) node; - BeginNode insertGuard = null; - BeginNode delete = null; - boolean inverted = false; - if (ifNode.probability(IfNode.TRUE_EDGE) == 0) { - insertGuard = ifNode.falseSuccessor(); - delete = ifNode.trueSuccessor(); - inverted = true; - } else if (ifNode.probability(IfNode.FALSE_EDGE) == 0) { - insertGuard = ifNode.trueSuccessor(); - delete = ifNode.falseSuccessor(); - } - if (insertGuard != null) { - GuardNode guard = graph.unique(new GuardNode(ifNode.compare(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, inverted, ifNode.leafGraphId())); - graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard))); - GraphUtil.killCFG(delete); - graph.removeSplit(ifNode, inverted ? IfNode.FALSE_EDGE : IfNode.TRUE_EDGE); - } - } - } - - } - -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; - -/** - * This phase culls unused FrameStates from the graph. - * It does a post order iteration over the graph, and - */ -public class CullFrameStatesPhase extends Phase { - - private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled"); - private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed"); - - @Override - protected void run(StructuredGraph graph) { - new CullFrameStates(graph.start(), new State(null)).apply(); - } - - public static class State implements MergeableState<State> { - - private FrameState lastFrameState; - - public State(FrameState lastFrameState) { - this.lastFrameState = lastFrameState; - } - - @Override - public boolean merge(MergeNode merge, List<State> withStates) { - FrameState stateAfter = merge.stateAfter(); - if (merge instanceof LoopBeginNode) { - if (stateAfter != null) { - lastFrameState = stateAfter; - } - return true; - } - metricMergesTraversed.increment(); - if (stateAfter != null) { - for (State other : withStates) { - if (other.lastFrameState != lastFrameState) { - lastFrameState = stateAfter; - return true; - } - } - metricFrameStatesCulled.increment(); - merge.setStateAfter(null); - if (stateAfter.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(stateAfter); - } - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) { - } - - @Override - public void afterSplit(FixedNode node) { - } - - @Override - public State clone() { - return new State(lastFrameState); - } - } - - public static class CullFrameStates extends PostOrderNodeIterator<State> { - - public CullFrameStates(FixedNode start, State initialState) { - super(start, initialState); - } - - @Override - protected void node(FixedNode node) { - if (node instanceof StateSplit) { - FrameState stateAfter = ((StateSplit) node).stateAfter(); - if (stateAfter != null) { - state.lastFrameState = stateAfter; - } - } - } - } - -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/DeadCodeEliminationPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - - -public class DeadCodeEliminationPhase extends Phase { - - // Metrics - private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); - - private NodeFlood flood; - - @Override - protected void run(StructuredGraph graph) { - this.flood = graph.createNodeFlood(); - - flood.add(graph.start()); - iterateSuccessors(); - disconnectCFGNodes(graph); - iterateInputs(graph); - deleteNodes(graph); - - // remove chained Merges - for (MergeNode merge : graph.getNodes(MergeNode.class)) { - if (merge.forwardEndCount() == 1 && !(merge instanceof LoopBeginNode)) { - graph.reduceTrivialMerge(merge); - } - } - } - - private void iterateSuccessors() { - for (Node current : flood) { - if (current instanceof EndNode) { - EndNode end = (EndNode) current; - flood.add(end.merge()); - } else { - for (Node successor : current.successors()) { - flood.add(successor); - } - } - } - } - - private void disconnectCFGNodes(StructuredGraph graph) { - for (EndNode node : graph.getNodes(EndNode.class)) { - if (!flood.isMarked(node)) { - MergeNode merge = node.merge(); - if (merge != null && flood.isMarked(merge)) { - // We are a dead end node leading to a live merge. - merge.removeEnd(node); - } - } - } - for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.class)) { - if (flood.isMarked(loop)) { - boolean reachable = false; - for (LoopEndNode end : loop.loopEnds()) { - if (flood.isMarked(end)) { - reachable = true; - break; - } - } - if (!reachable) { - Debug.log("Removing loop with unreachable end: %s", loop); - for (LoopEndNode end : loop.loopEnds().snapshot()) { - loop.removeEnd(end); - } - graph.reduceDegenerateLoopBegin(loop); - } - } - } - } - - private void deleteNodes(StructuredGraph graph) { - for (Node node : graph.getNodes()) { - if (!flood.isMarked(node)) { - node.clearInputs(); - node.clearSuccessors(); - } - } - for (Node node : graph.getNodes()) { - if (!flood.isMarked(node)) { - metricNodesRemoved.increment(); - node.safeDelete(); - } - } - } - - private void iterateInputs(StructuredGraph graph) { - for (Node node : graph.getNodes()) { - if (node instanceof LocalNode) { - flood.add(node); - } - if (flood.isMarked(node)) { - for (Node input : node.inputs()) { - flood.add(input); - } - } - } - for (Node current : flood) { - for (Node input : current.inputs()) { - flood.add(input); - } - } - } - -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ExpandBoxingNodesPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; - -public class ExpandBoxingNodesPhase extends Phase { - - private final BoxingMethodPool pool; - - public ExpandBoxingNodesPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - boxNode.expand(pool); - } - - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - unboxNode.expand(pool); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,294 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.extended.*; - -public class FloatingReadPhase extends Phase { - - private IdentityHashMap<LoopBeginNode, List<MemoryMap>> loopEndStatesMap; - - private static class LoopState { - public LoopBeginNode loopBegin; - public MemoryMap state; - public IdentityHashMap<PhiNode, Object> loopPhiLocations = new IdentityHashMap<>(); - public ValueNode loopEntryAnyLocation; - public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) { - this.loopBegin = loopBegin; - this.state = state; - this.loopEntryAnyLocation = loopEntryAnyLocation; - } - - @Override - public String toString() { - return "State@" + loopBegin; - } - } - - private class MemoryMap implements MergeableState<MemoryMap> { - private IdentityHashMap<Object, ValueNode> lastMemorySnapshot; - private LinkedList<LoopState> loops; - - public MemoryMap(MemoryMap memoryMap) { - lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); - loops = new LinkedList<>(memoryMap.loops); - } - - public MemoryMap() { - lastMemorySnapshot = new IdentityHashMap<>(); - loops = new LinkedList<>(); - } - - @Override - public String toString() { - return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString(); - } - - @Override - public boolean merge(MergeNode merge, List<MemoryMap> withStates) { - if (withStates.size() == 0) { - return true; - } - - int minLoops = loops.size(); - for (MemoryMap other : withStates) { - int otherLoops = other.loops.size(); - if (otherLoops < minLoops) { - minLoops = otherLoops; - } - } - while (loops.size() > minLoops) { - loops.pop(); - } - for (MemoryMap other : withStates) { - while (other.loops.size() > minLoops) { - other.loops.pop(); - } - } - - Set<Object> keys = new HashSet<>(); - for (Object key : lastMemorySnapshot.keySet()) { - keys.add(key); - } - for (MemoryMap other : withStates) { - assert other.loops.size() == loops.size(); - assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin; - for (Object key : other.lastMemorySnapshot.keySet()) { - keys.add(key); - } - } - @SuppressWarnings("unchecked") - IdentityHashMap<Object, ValueNode> newMemorySnapshot = (IdentityHashMap<Object, ValueNode>) lastMemorySnapshot.clone(); - - for (Object key : keys) { - ValueNode merged = lastMemorySnapshot.get(key); - if (merged == null) { - merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - int mergedStatesCount = 1; - boolean isPhi = false; - for (MemoryMap other : withStates) { - ValueNode otherValue = other.lastMemorySnapshot.get(key); - if (otherValue == null) { - otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - if (isPhi) { - ((PhiNode) merged).addInput(otherValue); - } else if (merged != otherValue) { - PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); - for (int j = 0; j < mergedStatesCount; j++) { - phi.addInput(merged); - } - phi.addInput(otherValue); - merged = phi; - isPhi = true; - newMemorySnapshot.put(key, phi); - } - mergedStatesCount++; - } - } - - lastMemorySnapshot = newMemorySnapshot; - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION)); - for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) { - PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin)); - phi.addInput(entry.getValue()); - entry.setValue(phi); - loopState.loopPhiLocations.put(phi, entry.getKey()); - } - loops.push(loopState); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) { - loopEndStatesMap.put(loopBegin, loopEndStates); - tryFinishLoopPhis(this, loopBegin); - } - - @Override - public void afterSplit(FixedNode node) { - // nothing - } - - @Override - public MemoryMap clone() { - return new MemoryMap(this); - } - } - - @Override - protected void run(StructuredGraph graph) { - loopEndStatesMap = new IdentityHashMap<>(); - new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) { - @Override - protected void node(FixedNode node) { - processNode(node, state); - } - }.apply(); - } - - private void processNode(FixedNode node, MemoryMap state) { - if (node instanceof ReadNode) { - processRead((ReadNode) node, state); - } else if (node instanceof WriteNode) { - processWrite((WriteNode) node, state); - } else if (node instanceof MemoryCheckpoint) { - processCheckpoint((MemoryCheckpoint) node, state); - } else if (node instanceof LoopExitNode) { - processLoopExit((LoopExitNode) node, state); - } - } - - private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { - processAnyLocationWrite((ValueNode) checkpoint, state); - } - - private static void processWrite(WriteNode writeNode, MemoryMap state) { - if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) { - processAnyLocationWrite(writeNode, state); - } - state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode); - } - - private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) { - for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(modifiying); - } - state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying); - state.loops.clear(); - } - - private void processRead(ReadNode readNode, MemoryMap state) { - StructuredGraph graph = (StructuredGraph) readNode.graph(); - assert readNode.getNullCheck() == false; - Object locationIdentity = readNode.location().locationIdentity(); - ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity); - FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies())); - floatingRead.setNullCheck(readNode.getNullCheck()); - ValueAnchorNode anchor = null; - for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) { - if (anchor == null) { - anchor = graph.add(new ValueAnchorNode()); - } - anchor.addAnchoredNode(guard); - } - if (anchor != null) { - graph.addAfterFixed(readNode, anchor); - } - graph.replaceFixedWithFloating(readNode, floatingRead); - } - - private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) { - ValueNode lastLocationAccess; - if (locationIdentity == LocationNode.FINAL_LOCATION) { - lastLocationAccess = null; - } else { - lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity); - if (lastLocationAccess == null) { - LoopState lastLoop = state.loops.peek(); - if (lastLoop == null) { - lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } else { - ValueNode phiInit; - if (state.loops.size() > 1) { - phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity); - } else { - phiInit = lastLoop.loopEntryAnyLocation; - } - PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin)); - phi.addInput(phiInit); - lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi); - lastLoop.loopPhiLocations.put(phi, locationIdentity); - tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin); - lastLocationAccess = phi; - } - state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess); - } - } - return lastLocationAccess; - } - - private static void processLoopExit(LoopExitNode exit, MemoryMap state) { - for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory))); - } - if (!state.loops.isEmpty()) { - state.loops.pop(); - } - } - - private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) { - List<MemoryMap> loopEndStates = loopEndStatesMap.get(loopBegin); - if (loopEndStates == null) { - return; - } - LoopState loopState = loopMemory.loops.get(0); - int i = 0; - while (loopState.loopBegin != loopBegin) { - loopState = loopMemory.loops.get(++i); - } - for (PhiNode phi : loopBegin.phis()) { - if (phi.type() == PhiType.Memory && phi.valueCount() == 1) { - Object location = loopState.loopPhiLocations.get(phi); - assert location != null : "unknown location for " + phi; - for (MemoryMap endState : loopEndStates) { - ValueNode otherNode = endState.lastMemorySnapshot.get(location); - if (otherNode == null) { - otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - phi.addInput(otherNode); - } - } - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/GlobalValueNumberingPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -public class GlobalValueNumberingPhase extends Phase { - - public static final DebugMetric metricGlobalValueNumberingHits = Debug.metric("GlobalValueNumberingHits"); - - @Override - protected void run(StructuredGraph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - for (Node n : graph.getNodes()) { - apply(n, visited, graph); - } - } - - private void apply(Node n, NodeBitMap visited, StructuredGraph compilerGraph) { - if (!visited.isMarked(n)) { - visited.mark(n); - for (Node input : n.inputs()) { - apply(input, visited, compilerGraph); - } - if (n.getNodeClass().valueNumberable()) { - Node newNode = compilerGraph.findDuplicate(n); - if (newNode != null) { - assert !(n instanceof FixedNode || newNode instanceof FixedNode); - n.replaceAtUsages(newNode); - n.safeDelete(); - metricGlobalValueNumberingHits.increment(); - Debug.log("GVN applied and new node is %1s", newNode); - } - } - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IdentifyBoxingPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; - -public class IdentifyBoxingPhase extends Phase { - - private final BoxingMethodPool pool; - - public IdentifyBoxingPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke invoke : graph.getInvokes()) { - tryIntrinsify(invoke); - } - } - - public void tryIntrinsify(Invoke invoke) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { - return; - } - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (pool.isSpecialMethod(targetMethod)) { - assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument"; - Kind returnKind = callTarget.returnKind(); - ValueNode sourceValue = callTarget.arguments().get(0); - - // Check whether this is a boxing or an unboxing. - Node newNode = null; - if (returnKind == Kind.Object) { - // We have a boxing method here. - assert Modifier.isStatic(targetMethod.accessFlags()) : "boxing method must be static"; - Kind sourceKind = targetMethod.signature().argumentKindAt(0); - newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.holder(), sourceKind, invoke.bci())); - } else { - // We have an unboxing method here. - assert !Modifier.isStatic(targetMethod.accessFlags()) : "unboxing method must be an instance method"; - newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue)); - } - - // Intrinsify the invoke to the special node. - invoke.intrinsify(newNode); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InliningPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; -import com.oracle.graal.compiler.util.*; -import com.oracle.graal.compiler.util.InliningUtil.InlineInfo; -import com.oracle.graal.compiler.util.InliningUtil.InliningCallback; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.internal.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - - -public class InliningPhase extends Phase implements InliningCallback { - /* - * - Detect method which only call another method with some parameters set to constants: void foo(a) -> void foo(a, b) -> void foo(a, b, c) ... - * These should not be taken into account when determining inlining depth. - * - honor the result of overrideInliningDecision(0, caller, invoke.bci, method, true); - */ - - private final TargetDescription target; - private final GraalCodeCacheProvider runtime; - - private final Collection<? extends Invoke> hints; - - private final PriorityQueue<InlineInfo> inlineCandidates = new PriorityQueue<>(); - private Assumptions assumptions; - - private final PhasePlan plan; - private final GraphCache cache; - private final WeightComputationPolicy weightComputationPolicy; - private final InliningPolicy inliningPolicy; - private final OptimisticOptimizations optimisticOpts; - - // Metrics - private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed"); - private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered"); - private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize"); - - public InliningPhase(TargetDescription target, GraalCodeCacheProvider runtime, Collection<? extends Invoke> hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { - this.target = target; - this.runtime = runtime; - this.hints = hints; - this.assumptions = assumptions; - this.cache = cache; - this.plan = plan; - this.optimisticOpts = optimisticOpts; - this.weightComputationPolicy = createWeightComputationPolicy(); - this.inliningPolicy = createInliningPolicy(); - } - - @SuppressWarnings("unchecked") - @Override - protected void run(final StructuredGraph graph) { - graph.createNodeMap(); - - if (hints != null) { - scanInvokes((Iterable<? extends Node>) Util.uncheckedCast(this.hints)); - } else { - scanInvokes(graph.getNodes(InvokeNode.class)); - scanInvokes(graph.getNodes(InvokeWithExceptionNode.class)); - } - - while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) { - InlineInfo candidate = inlineCandidates.remove(); - if (!candidate.invoke.node().isAlive()) { - continue; - } - // refresh infos - final InlineInfo info = InliningUtil.getInlineInfo(candidate.invoke, candidate.level, runtime, assumptions, this, optimisticOpts); - - boolean inline = Debug.scope("InliningDecisions", new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - return info != null && inliningPolicy.isWorthInlining(graph, info); - } - }); - - if (inline) { - int mark = graph.getMark(); - Iterable<Node> newNodes = null; - try { - info.inline(graph, runtime, this); - Debug.dump(graph, "after %s", info); - newNodes = graph.getNewNodes(mark); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph); - } -// if (GraalOptions.Intrinsify) { -// new IntrinsificationPhase(runtime).apply(graph); -// } - metricInliningPerformed.increment(); - } catch (BailoutException bailout) { - // TODO determine if we should really bail out of the whole compilation. - throw bailout; - } catch (AssertionError e) { - throw new GraalInternalError(e).addContext(info.toString()); - } catch (RuntimeException e) { - throw new GraalInternalError(e).addContext(info.toString()); - } catch (GraalInternalError e) { - throw e.addContext(info.toString()); - } - - if (newNodes != null && info.level < GraalOptions.MaximumInlineLevel) { - scanInvokes(newNodes); - } - } - } - - if (GraalOptions.Debug && graph.getNodeCount() >= GraalOptions.MaximumDesiredSize) { - Debug.scope("InliningDecisions", new Runnable() { - public void run() { - for (InlineInfo info : inlineCandidates) { - Debug.log("not inlining %s because inlining cut off by MaximumDesiredSize", InliningUtil.methodName(info)); - } - } - }); - - metricInliningStoppedByMaxDesiredSize.increment(); - } - } - - private void scanInvokes(final Iterable<? extends Node> nodes) { - Debug.scope("InliningDecisions", new Runnable() { - public void run() { - for (Node node : nodes) { - if (node != null) { - if (node instanceof Invoke) { - Invoke invoke = (Invoke) node; - scanInvoke(invoke); - } - for (Node usage : node.usages().filterInterface(Invoke.class).snapshot()) { - scanInvoke((Invoke) usage); - } - } - } - } - }); - } - - private void scanInvoke(Invoke invoke) { - InlineInfo info = InliningUtil.getInlineInfo(invoke, computeInliningLevel(invoke), runtime, assumptions, this, optimisticOpts); - if (info != null) { - metricInliningConsidered.increment(); - inlineCandidates.add(info); - } - } - - public static final Map<JavaMethod, Integer> parsedMethods = new HashMap<>(); - - - - private static final DebugMetric metricInliningRuns = Debug.metric("Runs"); - - @Override - public StructuredGraph buildGraph(final ResolvedJavaMethod method) { - metricInliningRuns.increment(); - if (GraalOptions.CacheGraphs && cache != null) { - StructuredGraph cachedGraph = cache.get(method); - if (cachedGraph != null) { - return cachedGraph; - } - } - StructuredGraph newGraph = new StructuredGraph(method); - if (plan != null) { - plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); - } - assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; - - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(newGraph); - new ComputeProbabilityPhase().apply(newGraph); - } - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph); - } - if (GraalOptions.Intrinsify) { - new IntrinsificationPhase(runtime).apply(newGraph); - } - if (GraalOptions.CullFrameStates) { - new CullFrameStatesPhase().apply(newGraph); - } - if (GraalOptions.CacheGraphs && cache != null) { - cache.put(newGraph); - } - return newGraph; - } - - @Override - public double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke) { - boolean preferred = hints != null && hints.contains(invoke); - return weightComputationPolicy.computeWeight(caller, method, invoke, preferred); - } - - public static int graphComplexity(StructuredGraph graph) { - int result = 0; - for (Node node : graph.getNodes()) { - if (node instanceof ConstantNode || node instanceof LocalNode || node instanceof BeginNode || node instanceof ReturnNode || node instanceof UnwindNode) { - result += 0; - } else if (node instanceof PhiNode) { - result += 5; - } else if (node instanceof MergeNode || node instanceof Invoke || node instanceof LoopEndNode || node instanceof EndNode) { - result += 0; - } else if (node instanceof ControlSplitNode) { - result += ((ControlSplitNode) node).blockSuccessorCount(); - } else { - result += 1; - } - } - return Math.max(1, result); - } - - - @Override - public void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { - assumptions.recordConcreteMethod(method, context, impl); - } - - @Override - public void recordMethodContentsAssumption(ResolvedJavaMethod method) { - if (assumptions != null) { - assumptions.recordMethodContents(method); - } - } - - private static int computeInliningLevel(Invoke invoke) { - int count = -1; - FrameState curState = invoke.stateAfter(); - while (curState != null) { - count++; - curState = curState.outerFrameState(); - } - return count; - } - - private static InliningPolicy createInliningPolicy() { - switch(GraalOptions.InliningPolicy) { - case 0: return new WeightBasedInliningPolicy(); - case 1: return new C1StaticSizeBasedInliningPolicy(); - case 2: return new MinimumCodeSizeBasedInliningPolicy(); - case 3: return new DynamicSizeBasedInliningPolicy(); - case 4: return new GreedySizeBasedInliningPolicy(); - default: - GraalInternalError.shouldNotReachHere(); - return null; - } - } - - private static WeightComputationPolicy createWeightComputationPolicy() { - switch(GraalOptions.WeightComputationPolicy) { - case 0: throw new GraalInternalError("removed because of invokation counter changes"); - case 1: return new BytecodeSizeBasedWeightComputationPolicy(); - case 2: return new ComplexityBasedWeightComputationPolicy(); - default: - GraalInternalError.shouldNotReachHere(); - return null; - } - } - - private interface InliningPolicy { - boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info); - } - - private static class WeightBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - if (!checkCompiledCodeSize(info)) { - return false; - } - - double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, callerGraph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp; - if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) { - Debug.log("not inlining %s (cut off by weight %e)", InliningUtil.methodName(info), info.weight); - return false; - } - - Debug.log("inlining %s (weight %f): %s", InliningUtil.methodName(info), info.weight); - return true; - } - } - - private static class C1StaticSizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize); - return decideSizeBasedInlining(info, maxSize); - } - } - - private static class MinimumCodeSizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - assert GraalOptions.ProbabilityAnalysis; - if (!checkCompiledCodeSize(info)) { - return false; - } - - double inlineWeight = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); - double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize * inlineWeight; - maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize); - - return decideSizeBasedInlining(info, maxSize); - } - } - - private static class DynamicSizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - assert GraalOptions.ProbabilityAnalysis; - if (!checkCompiledCodeSize(info)) { - return false; - } - - double inlineBoost = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()) + Math.log10(Math.max(1, info.invoke.probability() - GraalOptions.ProbabilityCapForInlining + 1)); - double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize; - maxSize = maxSize + maxSize * inlineBoost; - maxSize = Math.min(GraalOptions.MaximumGreedyInlineSize, Math.max(GraalOptions.MaximumTrivialSize, maxSize)); - - return decideSizeBasedInlining(info, maxSize); - } - } - - private static class GreedySizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - assert GraalOptions.ProbabilityAnalysis; - if (!checkCompiledCodeSize(info)) { - return false; - } - - double maxSize = GraalOptions.MaximumGreedyInlineSize; - if (GraalOptions.InliningBonusPerTransferredValue != 0) { - Signature signature = info.invoke.methodCallTarget().targetMethod().signature(); - int transferredValues = signature.argumentCount(!Modifier.isStatic(info.invoke.methodCallTarget().targetMethod().accessFlags())); - if (signature.returnKind() != Kind.Void) { - transferredValues++; - } - maxSize += transferredValues * GraalOptions.InliningBonusPerTransferredValue; - } - - double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); - maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * maxSize * inlineRatio; - maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize); - - return decideSizeBasedInlining(info, maxSize); - } - } - - private static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) { - boolean success = info.weight <= maxSize; - if (DebugScope.getInstance().isLogEnabled()) { - String formatterString = success ? "inlining %s (size %f <= %f)" : "not inlining %s (too large %f > %f)"; - Debug.log(formatterString, InliningUtil.methodName(info), info.weight, maxSize); - } - return success; - } - - private static boolean checkCompiledCodeSize(InlineInfo info) { - if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) { - Debug.log("not inlining %s (CompiledCodeSize %d > %d)", InliningUtil.methodName(info), info.compiledCodeSize(), GraalOptions.SmallCompiledCodeSize); - return false; - } - return true; - } - - - private interface WeightComputationPolicy { - double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke); - } - - private static class BytecodeSizeBasedWeightComputationPolicy implements WeightComputationPolicy { - @Override - public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { - double codeSize = method.codeSize(); - if (preferredInvoke) { - codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis; - } - return codeSize; - } - } - - private static class ComplexityBasedWeightComputationPolicy implements WeightComputationPolicy { - @Override - public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { - double complexity = method.compilationComplexity(); - if (preferredInvoke) { - complexity = complexity / GraalOptions.BoostInliningForEscapeAnalysis; - } - return complexity; - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class InsertStateAfterPlaceholderPhase extends Phase { - - private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, LIRLowerable, Canonicalizable { - public PlaceholderNode() { - super(StampFactory.forVoid()); - } - - @Override - public void generate(LIRGeneratorTool gen) { - // nothing to do - } - - @Override - public boolean hasSideEffect(CodeCacheProvider runtime) { - return false; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (stateAfter() == null) { - return null; - } - return this; - } - } - - @Override - protected void run(StructuredGraph graph) { - for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { - PlaceholderNode p = graph.add(new PlaceholderNode()); - p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI))); - graph.addBeforeFixed(ret, p); - } - } - -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IntrinsificationPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.util.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; - -public class IntrinsificationPhase extends Phase { - - private final GraalCodeCacheProvider runtime; - - public IntrinsificationPhase(GraalCodeCacheProvider runtime) { - this.runtime = runtime; - } - - @Override - protected void run(StructuredGraph graph) { - for (InvokeNode invoke : graph.getNodes(InvokeNode.class)) { - tryIntrinsify(invoke, runtime); - } - for (InvokeWithExceptionNode invoke : graph.getNodes(InvokeWithExceptionNode.class)) { - tryIntrinsify(invoke, runtime); - } - } - - public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { - return getIntrinsicGraph(invoke, target, runtime) != null; - } - - private static void tryIntrinsify(Invoke invoke, GraalCodeCacheProvider runtime) { - if (invoke.callTarget() instanceof MethodCallTargetNode && invoke.methodCallTarget().targetMethod() != null) { - tryIntrinsify(invoke, invoke.methodCallTarget().targetMethod(), runtime); - } - } - - private static void tryIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { - StructuredGraph intrinsicGraph = getIntrinsicGraph(invoke, target, runtime); - if (intrinsicGraph != null) { - Debug.log(" > Intrinsify %s", target); - InliningUtil.inline(invoke, intrinsicGraph, true); - } - } - - private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { - StructuredGraph intrinsicGraph = (StructuredGraph) target.compilerStorage().get(Graph.class); - if (intrinsicGraph == null) { - // TODO remove once all intrinsics are available via compilerStorage - intrinsicGraph = runtime.intrinsicGraph(invoke.stateAfter().method(), invoke.bci(), target, invoke.callTarget().arguments()); - } - return intrinsicGraph; - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IterativeCheckCastEliminationPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Graph.InputChangedListener; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - - -public class IterativeCheckCastEliminationPhase extends Phase { - private final TargetDescription target; - private final MetaAccessProvider runtime; - private final Assumptions assumptions; - - public IterativeCheckCastEliminationPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { - this.target = target; - this.runtime = runtime; - this.assumptions = assumptions; - } - - @Override - protected void run(StructuredGraph graph) { - Set<Node> canonicalizationRoots = new HashSet<>(); - CheckCastEliminationPhase eliminate = new CheckCastEliminationPhase(); - Listener listener = new Listener(canonicalizationRoots); - while (true) { - graph.trackInputChange(listener); - eliminate.apply(graph); - graph.stopTrackingInputChange(); - if (canonicalizationRoots.isEmpty()) { - break; - } - new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots, null).apply(graph); - canonicalizationRoots.clear(); - } - } - - private static class Listener implements InputChangedListener { - private final Set<Node> canonicalizationRoots; - public Listener(Set<Node> canonicalizationRoots) { - this.canonicalizationRoots = canonicalizationRoots; - } - @Override - public void inputChanged(Node node) { - canonicalizationRoots.add(node); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopSafepointInsertionPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.util.*; - -/** - * Adds safepoints to loops. - */ -public class LoopSafepointInsertionPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - nextLoop: - for (LoopEndNode loopEnd : graph.getNodes(LoopEndNode.class)) { - if (!loopEnd.canSafepoint()) { - continue; - } - if (GraalOptions.OptSafepointElimination) { - // We 'eliminate' safepoints by simply never placing them into loops that have at least one call - NodeIterable<FixedNode> it = NodeIterators.dominators(loopEnd).until(loopEnd.loopBegin()); - for (FixedNode n : it) { - if (n instanceof Invoke) { - continue nextLoop; - } - } - } - SafepointNode safepoint = graph.add(new SafepointNode()); - graph.addBeforeFixed(loopEnd, safepoint); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoweringPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.schedule.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; - -/** - * Processes all {@link Lowerable} nodes to do their lowering. - */ -public class LoweringPhase extends Phase { - - final class LoweringToolImpl implements LoweringTool { - - final FixedNode guardAnchor; - final NodeBitMap activeGuards; - FixedWithNextNode lastFixedNode; - - public LoweringToolImpl(FixedNode guardAnchor, NodeBitMap activeGuards) { - this.guardAnchor = guardAnchor; - this.activeGuards = activeGuards; - } - - @Override - public GraalCodeCacheProvider getRuntime() { - return runtime; - } - - @Override - public ValueNode createNullCheckGuard(ValueNode object, long leafGraphId) { - return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, leafGraphId); - } - - @Override - public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, long leafGraphId) { - return createGuard(condition, deoptReason, action, false, leafGraphId); - } - - @Override - public Assumptions assumptions() { - return assumptions; - } - - @Override - public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId) { - if (GraalOptions.OptEliminateGuards) { - for (Node usage : condition.usages()) { - if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) { - return (ValueNode) usage; - } - } - } - GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, leafGraphId)); - if (GraalOptions.OptEliminateGuards) { - activeGuards.grow(); - activeGuards.mark(newGuard); - } - return newGuard; - } - - public FixedWithNextNode lastFixedNode() { - return lastFixedNode; - } - } - - private final GraalCodeCacheProvider runtime; - private final Assumptions assumptions; - - public LoweringPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) { - this.runtime = runtime; - this.assumptions = assumptions; - } - - private static boolean containsLowerable(NodeIterable<Node> nodes) { - for (Node n : nodes) { - if (n instanceof Lowerable) { - return true; - } - } - return false; - } - - @Override - protected void run(final StructuredGraph graph) { - int i = 0; - NodeBitMap processed = graph.createNodeBitMap(); - while (true) { - int mark = graph.getMark(); - final SchedulePhase schedule = new SchedulePhase(); - schedule.apply(graph, false); - - processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed); - Debug.dump(graph, "Lowering iteration %d", i++); - new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph); - - if (!containsLowerable(graph.getNewNodes(mark))) { - // No new lowerable nodes - done! - break; - } - assert graph.verify(); - processed.grow(); - } - } - - private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor, SchedulePhase schedule, NodeBitMap processed) { - - FixedNode anchor = parentAnchor; - if (anchor == null) { - anchor = block.getBeginNode(); - } - process(block, activeGuards, anchor, schedule, processed); - - // Process always reached block first. - Block alwaysReachedBlock = block.getPostdominator(); - if (alwaysReachedBlock != null && alwaysReachedBlock.getDominator() == block) { - processBlock(alwaysReachedBlock, activeGuards, anchor, schedule, processed); - } - - // Now go for the other dominators. - for (Block dominated : block.getDominated()) { - if (dominated != alwaysReachedBlock) { - assert dominated.getDominator() == block; - processBlock(dominated, activeGuards, null, schedule, processed); - } - } - - if (parentAnchor == null && GraalOptions.OptEliminateGuards) { - for (GuardNode guard : anchor.usages().filter(GuardNode.class)) { - activeGuards.clear(guard); - } - } - } - - private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor, SchedulePhase schedule, NodeBitMap processed) { - - final LoweringToolImpl loweringTool = new LoweringToolImpl(anchor, activeGuards); - - // Lower the instructions of this block. - List<ScheduledNode> nodes = schedule.nodesFor(b); - - for (Node node : nodes) { - FixedNode lastFixedNext = null; - if (node instanceof FixedWithNextNode) { - FixedWithNextNode fixed = (FixedWithNextNode) node; - lastFixedNext = fixed.next(); - loweringTool.lastFixedNode = fixed; - } - - if (node.isAlive() && !processed.isMarked(node)) { - processed.mark(node); - if (node instanceof Lowerable) { - ((Lowerable) node).lower(loweringTool); - } - } - - if (loweringTool.lastFixedNode == node && !node.isAlive()) { - if (lastFixedNext == null) { - loweringTool.lastFixedNode = null; - } else { - Node prev = lastFixedNext.predecessor(); - if (prev != node && prev instanceof FixedWithNextNode) { - loweringTool.lastFixedNode = (FixedWithNextNode) prev; - } else if (lastFixedNext instanceof FixedWithNextNode) { - loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext; - } else { - loweringTool.lastFixedNode = null; - } - } - } - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/Phase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; - -public abstract class Phase { - - private String name; - private static final DebugMetric metricPhaseRuns = Debug.metric("Runs"); - protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes"); - - protected Phase() { - this.name = this.getClass().getSimpleName(); - if (name.endsWith("Phase")) { - name = name.substring(0, name.length() - "Phase".length()); - } - } - - protected Phase(String name) { - this.name = name; - } - - protected String getDetailedName() { - return getName(); - } - - public final void apply(final StructuredGraph graph) { - apply(graph, true); - } - - public final void apply(final StructuredGraph graph, final boolean dumpGraph) { - Debug.scope(name, this, new Runnable() { - public void run() { - Phase.this.run(graph); - metricPhaseRuns.increment(); - if (dumpGraph) { - Debug.dump(graph, "After phase %s", name); - } - assert graph.verify(); - } - }); - } - - public final String getName() { - return name; - } - - protected abstract void run(StructuredGraph graph); -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhasePlan.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.nodes.*; - -/** - * Tells the compiler about additional phases that need to be executed during compilation. - */ -public class PhasePlan { - /** - * The compilation is split into the following sections: - * ======================================================================== - * Period 1: High-level nodes. (Graph building) - * ======================================================================== - * Runtime-specific lowering. - * ======================================================================== - * Period 2: Mid-level nodes. (Memory dependence graph) - * ======================================================================== - * Target-specific lowering, de-SSA. - * ======================================================================== - * Period 3: Low-level nodes. (Register allocation, code generation) - * ======================================================================== - * - * A compiler extension phase can chose to run at the end of periods 1-3. - */ - public static enum PhasePosition { - AFTER_PARSING, - HIGH_LEVEL, - MID_LEVEL, - LOW_LEVEL - } - - @SuppressWarnings("unchecked") - private final ArrayList<Phase>[] phases = new ArrayList[PhasePosition.values().length]; - private final Set<Class<? extends Phase>> disabledPhases = new HashSet<>(); - - public void addPhase(PhasePosition pos, Phase phase) { - if (phases[pos.ordinal()] == null) { - phases[pos.ordinal()] = new ArrayList<>(); - } - phases[pos.ordinal()].add(phase); - } - - public void runPhases(PhasePosition pos, StructuredGraph graph) { - if (phases[pos.ordinal()] != null) { - for (Phase p : phases[pos.ordinal()]) { - p.apply(graph); - } - } - } - - public void disablePhase(Class<? extends Phase> clazz) { - disabledPhases.add(clazz); - } - - public boolean isPhaseDisabled(Class<? extends Phase> clazz) { - return disabledPhases.contains(clazz); - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhiStampPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.nodes.*; - -public class PhiStampPhase extends Phase { - @Override - protected void run(StructuredGraph graph) { - // Infer phis stopping at loop phis. - for (PhiNode phi : graph.getNodes(PhiNode.class)) { - inferPhi(phi); - } - - // Start iterative inference for loop phis. - if (graph.hasLoops()) { - for (PhiNode phi : graph.getNodes(PhiNode.class)) { - if (phi.isLoopPhi()) { - iterativeInferPhi(phi); - } - } - } - } - - private void iterativeInferPhi(PhiNode phi) { - if (phi.inferPhiStamp()) { - for (PhiNode phiUsage : phi.usages().filter(PhiNode.class)) { - iterativeInferPhi(phiUsage); - } - } - } - - private void inferPhi(PhiNode phi) { - for (PhiNode phiInput : phi.values().filter(PhiNode.class)) { - if (!phiInput.isLoopPhi()) { - inferPhi(phiInput); - } - } - phi.inferPhiStamp(); - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.extended.*; - -public class ReadEliminationPhase extends Phase { - private Queue<PhiNode> newPhis; - - @Override - protected void run(StructuredGraph graph) { - newPhis = new LinkedList<>(); - for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) { - if (isReadEliminable(n)) { - NodeMap<ValueNode> nodeMap = n.graph().createNodeMap(); - ValueNode value = getValue(n, n.lastLocationAccess(), nodeMap); - Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value); - graph.replaceFloating(n, value); - } - } - } - - private boolean isReadEliminable(FloatingReadNode n) { - return isWrites(n, n.lastLocationAccess(), n.graph().createNodeBitMap()); - } - - private boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) { - if (lastLocationAccess == null) { - return false; - } - if (visited.isMarked(lastLocationAccess)) { - return true; // dataflow loops must come from Phis assume them ok until proven wrong - } - if (lastLocationAccess instanceof ValueProxyNode) { - return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited); - } - if (lastLocationAccess instanceof WriteNode) { - WriteNode other = (WriteNode) lastLocationAccess; - return other.object() == n.object() && other.location() == n.location(); - } - if (lastLocationAccess instanceof PhiNode) { - visited.mark(lastLocationAccess); - for (ValueNode value : ((PhiNode) lastLocationAccess).values()) { - if (!isWrites(n, value, visited)) { - return false; - } - } - return true; - } - return false; - } - - private ValueNode getValue(FloatingReadNode n, Node lastLocationAccess, NodeMap<ValueNode> nodeMap) { - ValueNode exisiting = nodeMap.get(lastLocationAccess); - if (exisiting != null) { - return exisiting; - } - if (lastLocationAccess instanceof ValueProxyNode) { - ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess; - ValueNode value = getValue(n, proxy.value(), nodeMap); - return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value)); - } - if (lastLocationAccess instanceof WriteNode) { - return ((WriteNode) lastLocationAccess).value(); - } - if (lastLocationAccess instanceof PhiNode) { - PhiNode phi = (PhiNode) lastLocationAccess; - PhiNode newPhi = phi.graph().add(new PhiNode(n.kind(), phi.merge())); - nodeMap.set(lastLocationAccess, newPhi); - for (ValueNode value : phi.values()) { - newPhi.addInput(getValue(n, value, nodeMap)); - } - newPhis.add(newPhi); - return newPhi; - } - throw GraalInternalError.shouldNotReachHere(); - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.nodes.*; - -public class RemoveValueProxyPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) { - graph.replaceFloating(vpn, vpn.value()); - } - for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) { - FrameState stateAfter = exit.stateAfter(); - if (stateAfter != null) { - exit.setStateAfter(null); - if (stateAfter.usages().count() == 0) { - stateAfter.safeDelete(); - } - } - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/TailDuplicationPhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,551 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -/** - * This class is a phase that looks for opportunities for tail duplication. The static method - * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail duplication from - * other places, e.g., inlining. - */ -public class TailDuplicationPhase extends Phase { - - /* - * Various metrics on the circumstances in which tail duplication was/wasn't performed. - */ - private static final DebugMetric metricDuplicationMonitors = Debug.metric("DuplicationMonitors"); - private static final DebugMetric metricDuplicationEnd = Debug.metric("DuplicationEnd"); - private static final DebugMetric metricDuplicationEndPerformed = Debug.metric("DuplicationEndPerformed"); - private static final DebugMetric metricDuplicationOther = Debug.metric("DuplicationOther"); - private static final DebugMetric metricDuplicationOtherPerformed = Debug.metric("DuplicationOtherPerformed"); - - /** - * 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(MergeNode 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(MergeNode merge, int fixedNodeCount) { - if (fixedNodeCount < GraalOptions.TailDuplicationTrivialSize) { - return true; - } - HashSet<PhiNode> improvements = new HashSet<>(); - for (PhiNode phi : merge.phis()) { - Stamp phiStamp = phi.stamp(); - for (ValueNode input : phi.values()) { - if (!input.stamp().equals(phiStamp)) { - improvements.add(phi); - break; - } - } - } - if (improvements.isEmpty()) { - return false; - } - FixedNode current = merge; - int opportunities = 0; - while (current instanceof FixedWithNextNode) { - current = ((FixedWithNextNode) current).next(); - 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(MergeNode merge, int fixedNodeCount) { - return true; - } - }; - - @Override - protected void run(StructuredGraph graph) { - // A snapshot is taken here, so that new MergeNode instances aren't considered for tail duplication. - for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { - if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) { - tailDuplicate(merge, DEFAULT_DECISION, null); - } - } - } - - /** - * 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 MergeNode#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. - */ - public static void tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List<PiNode> replacements) { - assert !(merge instanceof LoopBeginNode); - assert replacements == null || replacements.size() == merge.forwardEndCount(); - FixedNode fixed = merge; - int fixedCount = 0; - boolean containsMonitor = false; - while (fixed instanceof FixedWithNextNode) { - if (fixed instanceof MonitorEnterNode || fixed instanceof MonitorExitNode) { - containsMonitor = true; - } - fixed = ((FixedWithNextNode) fixed).next(); - fixedCount++; - } - if (containsMonitor) { - // cannot currently be handled - // TODO (ls) re-evaluate this limitation after changes to the lock representation and the LIR generator - metricDuplicationMonitors.increment(); - } else if (fixedCount > 1) { - if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) { - metricDuplicationEnd.increment(); - if (decision.doTransform(merge, fixedCount)) { - metricDuplicationEndPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); - } - } else if (merge.stateAfter() != null) { - metricDuplicationOther.increment(); - if (decision.doTransform(merge, fixedCount)) { - metricDuplicationOtherPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); - } - } - } - } - - /** - * This class encapsulates one tail duplication operation on a specific {@link MergeNode}. - */ - private static class DuplicationOperation { - - private final MergeNode merge; - private final StructuredGraph graph; - - private final HashMap<ValueNode, PhiNode> bottomPhis = new HashMap<>(); - private final List<PiNode> replacements; - - /** - * 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(MergeNode merge, List<PiNode> replacements) { - this.merge = merge; - this.replacements = replacements; - this.graph = (StructuredGraph) merge.graph(); - } - - /** - * Performs the actual tail duplication: - * <ul> - * <li>Creates a new {@link ValueAnchorNode} at the beginning of the duplicated area, an transfers all - * dependencies from the merge to this anchor.</li> - * <li>Determines the set of fixed nodes to be duplicated.</li> - * <li>Creates the new merge at the bottom of the duplicated area.</li> - * <li>Determines the complete set of duplicated nodes.</li> - * <li>Performs the actual duplication.</li> - * </ul> - */ - private void duplicate() { - Debug.log("tail duplication at merge %s in %s (prob %f)", merge, graph.method(), merge.probability()); - - ValueAnchorNode 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<FixedNode> 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(); - } - - EndNode endAfter = createNewMerge(fixed, stateAfter); - MergeNode mergeAfter = endAfter.merge(); - fixedNodes.add(endAfter); - final HashSet<Node> duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter); - mergeAfter.clearEnds(); - expandDuplicated(duplicatedNodes, mergeAfter); - retargetDependencies(duplicatedNodes, anchor); - - List<EndNode> endSnapshot = merge.forwardEnds().snapshot(); - List<PhiNode> phiSnapshot = merge.phis().snapshot(); - - int endIndex = 0; - for (final EndNode forwardEnd : merge.forwardEnds()) { - Map<Node, Node> duplicates; - if (replacements == null || replacements.get(endIndex) == null) { - duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null); - } else { - HashMap<Node, Node> replace = new HashMap<>(); - replace.put(replacements.get(endIndex).object(), replacements.get(endIndex)); - duplicates = graph.addDuplicates(duplicatedNodes, replace); - } - for (Map.Entry<ValueNode, PhiNode> 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 - FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor); - ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate); - // move dependencies on the ValueAnchorNode to the previous BeginNode - BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate); - anchorDuplicate.replaceAtUsages(prevBegin); - - // re-wire the phi duplicates to the correct input - for (PhiNode phi : phiSnapshot) { - PhiNode phiDuplicate = (PhiNode) duplicates.get(phi); - for (Node usage : phiDuplicate.usages()) { - if (usage instanceof ValueNode) { - ((ValueNode) usage).dependencies().add(prevBegin); - } - } - phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd)); - phiDuplicate.safeDelete(); - } - endIndex++; - } - GraphUtil.killCFG(merge); - for (EndNode 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); - } - } - 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 ValueAnchorNode addValueAnchor() { - ValueAnchorNode anchor = graph.add(new ValueAnchorNode()); - graph.addAfterFixed(merge, anchor); - for (Node usage : merge.usages().snapshot()) { - if (usage instanceof PhiNode && ((PhiNode) usage).merge() == merge) { - // nothing to do - } else { - usage.replaceFirstInput(merge, 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 HashSet<Node> buildDuplicatedNodeSet(final ArrayList<FixedNode> fixedNodes, FrameState stateAfter) { - final NodeBitMap aboveBound = graph.createNodeBitMap(); - final NodeBitMap belowBound = graph.createNodeBitMap(); - - final Deque<Node> 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<Node> aboveClosure = new NodeClosure<Node>() { - - @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); - HashSet<Node> result = new HashSet<>(); - 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 EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) { - MergeNode newBottomMerge = graph.add(new MergeNode()); - newBottomMerge.setProbability(successor.probability()); - 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: - * <ul> - * <li>{@link ValueNode}s that have usages on the outside need to be replaced with phis for the outside usages.</li> - * <li>Non-{@link ValueNode} nodes that have outside usages (frame states, virtual object states, ...) need to - * be cloned immediately for the outside usages.</li> - * <li>Nodes that have a {@link StampFactory#extension()} or {@link StampFactory#condition()} stamp need to be - * cloned immediately for the outside usages.</li> - * <li>Dependencies into the duplicated nodes will be replaced with dependencies on the merge.</li> - * <li>Outside non-{@link ValueNode}s with usages within the duplicated set of nodes need to also be duplicated. - * </li> - * <li>Outside {@link ValueNode}s with {@link StampFactory#extension()} or {@link StampFactory#condition()} - * stamps that have usages within the duplicated set of nodes need to also be duplicated.</li> - * </ul> - * - * @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(HashSet<Node> duplicatedNodes, MergeNode newBottomMerge) { - Deque<Node> worklist = new ArrayDeque<>(duplicatedNodes); - - while (!worklist.isEmpty()) { - Node duplicated = worklist.remove(); - if (hasUsagesOutside(duplicated, duplicatedNodes)) { - boolean cloneForOutsideUsages = false; - if (duplicated instanceof ValueNode) { - ValueNode node = (ValueNode) duplicated; - if (node.stamp() == StampFactory.dependency()) { - // re-route dependencies to the merge - replaceUsagesOutside(node, newBottomMerge, duplicatedNodes); - // TODO(ls) maybe introduce phis for dependencies - } else if (node.stamp() == StampFactory.extension() || node.stamp() == StampFactory.condition()) { - cloneForOutsideUsages = true; - } else { - // introduce a new phi - PhiNode newPhi = bottomPhis.get(node); - if (newPhi == null) { - newPhi = graph.add(new PhiNode(node.kind(), newBottomMerge)); - bottomPhis.put(node, newPhi); - newPhi.addInput(node); - } - replaceUsagesOutside(node, newPhi, duplicatedNodes); - } - } else { - cloneForOutsideUsages = true; - } - if (cloneForOutsideUsages) { - // clone the offending node to the outside - Node newOutsideClone = duplicated.copyWithInputs(); - replaceUsagesOutside(duplicated, newOutsideClone, duplicatedNodes); - // this might cause other nodes to have outside usages, we need to look at those as well - for (Node input : newOutsideClone.inputs()) { - if (duplicatedNodes.contains(input)) { - worklist.add(input); - } - } - } - } - // check if this node has an input that lies outside and cannot be shared - for (Node input : duplicated.inputs()) { - if (!duplicatedNodes.contains(input)) { - boolean duplicateInput = false; - if (input instanceof VirtualState) { - duplicateInput = true; - } else if (input instanceof ValueNode) { - Stamp inputStamp = ((ValueNode) input).stamp(); - if (inputStamp == StampFactory.extension() || inputStamp == StampFactory.condition()) { - duplicateInput = true; - } - } - if (duplicateInput) { - duplicatedNodes.add(input); - worklist.add(input); - } - } - } - } - } - - /** - * Moves all depdendencies that point outside the duplicated area to the supplied value anchor node. - * - * @param duplicatedNodes The set of duplicated nodes. - * @param anchor The node that will be the new target for all dependencies that point outside the duplicated set of nodes. - */ - private static void retargetDependencies(HashSet<Node> duplicatedNodes, ValueAnchorNode anchor) { - for (Node node : duplicatedNodes) { - if (node instanceof ValueNode) { - NodeInputList<ValueNode> dependencies = ((ValueNode) node).dependencies(); - for (int i = 0; i < dependencies.size(); i++) { - Node dependency = dependencies.get(i); - if (dependency != null && !duplicatedNodes.contains(dependency)) { - Debug.log("retargeting dependency %s to %s on %s", dependency, anchor, node); - dependencies.set(i, anchor); - } - } - } - } - } - - /** - * Checks if the given node has usages that are not within the given set of nodes. - * - * @param node The node whose usages are checked. - * @param nodeSet The set of nodes that are considered to be "within". - * @return true if the given node has usages on the outside, false otherwise. - */ - private static boolean hasUsagesOutside(Node node, HashSet<Node> nodeSet) { - for (Node usage : node.usages()) { - if (!nodeSet.contains(usage)) { - return true; - } - } - return false; - } - - /** - * Replaces the given node with the given replacement at all usages that are not within the given set of nodes. - * - * @param node The node to be replaced at outside usages. - * @param replacement The node that replaced the given node at outside usages. - * @param nodeSet The set of nodes that are considered to be "within". - */ - private static void replaceUsagesOutside(Node node, Node replacement, HashSet<Node> nodeSet) { - for (Node usage : node.usages().snapshot()) { - if (!nodeSet.contains(usage)) { - usage.replaceFirstInput(node, replacement); - } - } - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/BlockClosure.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.schedule; - -import com.oracle.graal.lir.cfg.*; - -/** - * The {@code BlockClosure} interface represents a closure for iterating over blocks. - */ -public interface BlockClosure { - void apply(Block block); -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,399 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.schedule; - -import java.util.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.Verbosity; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.virtual.*; - -public class SchedulePhase extends Phase { - private ControlFlowGraph cfg; - private NodeMap<Block> earliestCache; - - /** - * Map from blocks to the nodes in each block. - */ - private BlockMap<List<ScheduledNode>> blockToNodesMap; - - public SchedulePhase() { - super("Schedule"); - } - - @Override - protected void run(StructuredGraph graph) { - cfg = ControlFlowGraph.compute(graph, true, true, true, false); - earliestCache = graph.createNodeMap(); - blockToNodesMap = new BlockMap<>(cfg); - - assignBlockToNodes(graph); - sortNodesWithinBlocks(graph); - } - - /** - * Sets {@link ScheduledNode#scheduledNext} on all scheduled nodes in all blocks using the scheduling built by @link {@link #run(StructuredGraph)}. - * This method should thus only be called when run has been successfully executed. - */ - public void scheduleGraph() { - assert blockToNodesMap != null : "cannot set scheduledNext before run has been executed"; - for (Block block : cfg.getBlocks()) { - List<ScheduledNode> nodeList = blockToNodesMap.get(block); - ScheduledNode last = null; - for (ScheduledNode node : nodeList) { - if (last != null) { - last.setScheduledNext(node); - } - last = node; - } - } - } - - public ControlFlowGraph getCFG() { - return cfg; - } - - /** - * Gets the map from each block to the nodes in the block. - */ - public BlockMap<List<ScheduledNode>> getBlockToNodesMap() { - return blockToNodesMap; - } - - /** - * Gets the nodes in a given block. - */ - public List<ScheduledNode> nodesFor(Block block) { - return blockToNodesMap.get(block); - } - - private void assignBlockToNodes(StructuredGraph graph) { - for (Block block : cfg.getBlocks()) { - List<ScheduledNode> nodes = new ArrayList<>(); - assert blockToNodesMap.get(block) == null; - blockToNodesMap.put(block, nodes); - for (FixedNode node : block.getNodes()) { - nodes.add(node); - } - } - - for (Node n : graph.getNodes()) { - if (n instanceof ScheduledNode) { - assignBlockToNode((ScheduledNode) n); - } - } - } - - /** - * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are already assigned to a block. - */ - private void assignBlockToNode(ScheduledNode node) { - assert !node.isDeleted(); - - Block prevBlock = cfg.getNodeToBlock().get(node); - if (prevBlock != null) { - return; - } - // PhiNodes and FixedNodes should already have been placed in blocks by ControlFlowGraph.identifyBlocks - assert !(node instanceof PhiNode) : node; - assert !(node instanceof FixedNode) : node; - // if in CFG, schedule at the latest position possible in the outermost loop possible - Block latestBlock = latestBlock(node); - Block block; - if (latestBlock == null) { - block = earliestBlock(node); - } else if (GraalOptions.ScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) { - Block earliestBlock = earliestBlock(node); - block = scheduleOutOfLoops(node, latestBlock, earliestBlock); - assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; - } else { - block = latestBlock; - } - cfg.getNodeToBlock().set(node, block); - blockToNodesMap.get(block).add(node); - } - - /** - * Calculates the last block that the given node could be scheduled in, i.e., the common dominator of all usages. - * To do so all usages are also assigned to blocks. - */ - private Block latestBlock(ScheduledNode node) { - CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); - for (Node succ : node.successors().nonNull()) { - assert cfg.getNodeToBlock().get(succ) != null; - cdbc.apply(cfg.getNodeToBlock().get(succ)); - } - ensureScheduledUsages(node); - for (Node usage : node.usages()) { - blocksForUsage(node, usage, cdbc); - } - return cdbc.block; - } - - /** - * A closure that will calculate the common dominator of all blocks passed to its {@link #apply(Block)} method. - */ - private static class CommonDominatorBlockClosure implements BlockClosure { - public Block block; - public CommonDominatorBlockClosure(Block block) { - this.block = block; - } - @Override - public void apply(Block newBlock) { - this.block = getCommonDominator(this.block, newBlock); - } - } - - /** - * Determines the earliest block in which the given node can be scheduled. - */ - private Block earliestBlock(Node node) { - Block earliest = cfg.getNodeToBlock().get(node); - if (earliest != null) { - return earliest; - } - earliest = earliestCache.get(node); - if (earliest != null) { - return earliest; - } - /* - * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This implies that the - * inputs' blocks have a total ordering via their dominance relation. So in order to find the earliest block - * placement for this node we need to find the input block that is dominated by all other input blocks. - * - * While iterating over the inputs a set of dominator blocks of the current earliest placement is maintained. - * When the block of an input is not within this set, it becomes the current earliest placement and the list of - * dominator blocks is updated. - */ - BitSet dominators = new BitSet(cfg.getBlocks().length); - - assert node.predecessor() == null; - for (Node input : node.inputs().nonNull()) { - assert input instanceof ValueNode; - Block inputEarliest = earliestBlock(input); - if (!dominators.get(inputEarliest.getId())) { - earliest = inputEarliest; - do { - dominators.set(inputEarliest.getId()); - inputEarliest = inputEarliest.getDominator(); - } while(inputEarliest != null && !dominators.get(inputEarliest.getId())); - } - } - if (earliest == null) { - earliest = cfg.getStartBlock(); - } - earliestCache.set(node, earliest); - return earliest; - } - - - private static Block scheduleOutOfLoops(Node n, Block latestBlock, Block earliest) { - assert latestBlock != null : "no latest : " + n; - Block cur = latestBlock; - Block result = latestBlock; - while (cur.getLoop() != null && cur != earliest && cur.getDominator() != null) { - Block dom = cur.getDominator(); - if (dom.getLoopDepth() < result.getLoopDepth()) { - result = dom; - } - cur = dom; - } - return result; - } - - /** - * Passes all blocks that a specific usage of a node is in to a given closure. - * This is more complex than just taking the usage's block because of of PhiNodes and FrameStates. - * - * @param node the node that needs to be scheduled - * @param usage the usage whose blocks need to be considered - * @param closure the closure that will be called for each block - */ - private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) { - assert !(node instanceof PhiNode); - - if (usage instanceof PhiNode) { - // An input to a PhiNode is used at the end of the predecessor block that corresponds to the PhiNode input. - // One PhiNode can use an input multiple times, the closure will be called for each usage. - PhiNode phi = (PhiNode) usage; - MergeNode merge = phi.merge(); - Block mergeBlock = cfg.getNodeToBlock().get(merge); - assert mergeBlock != null : "no block for merge " + merge.toString(Verbosity.Id); - for (int i = 0; i < phi.valueCount(); ++i) { - if (phi.valueAt(i) == node) { - if (mergeBlock.getPredecessors().size() <= i) { - TTY.println(merge.toString()); - TTY.println(phi.toString()); - TTY.println(merge.cfgPredecessors().toString()); - TTY.println(mergeBlock.getPredecessors().toString()); - TTY.println(phi.inputs().toString()); - TTY.println("value count: " + phi.valueCount()); - } - closure.apply(mergeBlock.getPredecessors().get(i)); - } - } - } else if (usage instanceof VirtualState) { - // The following logic does not work if node is a PhiNode, but this method is never called for PhiNodes. - for (Node unscheduledUsage : usage.usages()) { - if (unscheduledUsage instanceof VirtualState) { - // If a FrameState is an outer FrameState this method behaves as if the inner FrameState was the actual usage, by recursing. - blocksForUsage(node, unscheduledUsage, closure); - } else if (unscheduledUsage instanceof MergeNode) { - // Only FrameStates can be connected to MergeNodes. - assert usage instanceof FrameState; - // If a FrameState belongs to a MergeNode then it's inputs will be placed at the common dominator of all EndNodes. - for (Node pred : unscheduledUsage.cfgPredecessors()) { - closure.apply(cfg.getNodeToBlock().get(pred)); - } - } else { - // For the time being, only FrameStates can be connected to StateSplits. - assert usage instanceof FrameState; - assert unscheduledUsage instanceof StateSplit; - // Otherwise: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) unscheduledUsage); - closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); - } - } - } else { - // All other types of usages: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) usage); - closure.apply(cfg.getNodeToBlock().get(usage)); - } - } - - private void ensureScheduledUsages(Node node) { - for (Node usage : node.usages().filter(ScheduledNode.class)) { - assignBlockToNode((ScheduledNode) usage); - } - // now true usages are ready - } - - private static Block getCommonDominator(Block a, Block b) { - if (a == null) { - return b; - } - if (b == null) { - return a; - } - return ControlFlowGraph.commonDominator(a, b); - } - - private void sortNodesWithinBlocks(StructuredGraph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - for (Block b : cfg.getBlocks()) { - sortNodesWithinBlock(b, visited); - } - } - - /** - * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over all inputs. - * This means that a node is added to the list after all its inputs have been processed. - */ - private void sortNodesWithinBlock(Block b, NodeBitMap visited) { - List<ScheduledNode> instructions = blockToNodesMap.get(b); - List<ScheduledNode> sortedInstructions = new ArrayList<>(instructions.size() + 2); - - assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; - assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; - - for (ScheduledNode i : instructions) { - addToSorting(b, i, sortedInstructions, visited); - } - - // Make sure that last node gets really last (i.e. when a frame state successor hangs off it). - Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1); - if (lastSorted != b.getEndNode()) { - int idx = sortedInstructions.indexOf(b.getEndNode()); - boolean canNotMove = false; - for (int i = idx + 1; i < sortedInstructions.size(); i++) { - if (sortedInstructions.get(i).inputs().contains(b.getEndNode())) { - canNotMove = true; - break; - } - } - if (canNotMove) { - if (b.getEndNode() instanceof ControlSplitNode) { - throw new GraalInternalError("Schedule is not possible : needs to move a node after the last node of the block which can not be move"). - addContext(lastSorted). - addContext(b.getEndNode()); - } - - //b.setLastNode(lastSorted); - } else { - sortedInstructions.remove(b.getEndNode()); - sortedInstructions.add(b.getEndNode()); - } - } - blockToNodesMap.put(b, sortedInstructions); - } - - private void addUnscheduledToSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited) { - if (state != null) { - // UnscheduledNodes should never be marked as visited. - assert !visited.isMarked(state); - - for (Node input : state.inputs()) { - if (input instanceof VirtualState) { - addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited); - } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); - } - } - } - } - - private void addToSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited) { - if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { - return; - } - - FrameState state = null; - WriteNode write = null; - for (Node input : i.inputs()) { - if (input instanceof WriteNode && !visited.isMarked(input) && cfg.getNodeToBlock().get(input) == b) { - assert write == null; - write = (WriteNode) input; - } else if (input instanceof FrameState) { - assert state == null; - state = (FrameState) input; - } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); - } - } - - addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); - visited.mark(i); - addUnscheduledToSorting(b, state, sortedInstructions, visited); - assert write == null || !visited.isMarked(write); - addToSorting(b, write, sortedInstructions, visited); - - // Now predecessors and inputs are scheduled => we can add this node. - sortedInstructions.add(i); - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/ArrayMap.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -/** - * The {@code ArrayMap} class implements an efficient one-level map which is implemented - * as an array. Note that because of the one-level array inside, this data structure performs best - * when the range of integer keys is small and densely used. Note that the implementation can - * handle arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1. - */ -public class ArrayMap<T> { - - private static final int INITIAL_SIZE = 5; // how big the initial array should be - private static final int EXTRA = 2; // how far on the left or right of a new element to grow - - Object[] map; - int low; - - /** - * Constructs a new {@code ArrayMap} with no initial assumptions. - */ - public ArrayMap() { - } - - /** - * Constructs a new {@code ArrayMap} that initially covers the specified interval. - * Note that this map will automatically expand if necessary later. - * @param low the low index, inclusive - * @param high the high index, exclusive - */ - public ArrayMap(int low, int high) { - this.low = low; - this.map = new Object[high - low + 1]; - } - - /** - * Puts a new value in the map at the specified index. - * @param i the index at which to store the value - * @param value the value to store at the specified index - */ - public void put(int i, T value) { - int index = i - low; - if (map == null) { - // no map yet - map = new Object[INITIAL_SIZE]; - low = index - 2; - map[INITIAL_SIZE / 2] = value; - } else if (index < 0) { - // grow backwards - growBackward(i, value); - } else if (index >= map.length) { - // grow forwards - growForward(i, value); - } else { - // no growth necessary - map[index] = value; - } - } - - /** - * Gets the value at the specified index in the map. - * @param i the index - * @return the value at the specified index; {@code null} if there is no value at the specified index, - * or if the index is out of the currently stored range - */ - public T get(int i) { - int index = i - low; - if (map == null || index < 0 || index >= map.length) { - return null; - } - Class<T> type = null; - return Util.uncheckedCast(type, map[index]); - } - - public int length() { - return map.length; - } - - private void growBackward(int i, T value) { - int nlow = i - EXTRA; - Object[] nmap = new Object[low - nlow + map.length]; - System.arraycopy(map, 0, nmap, low - nlow, map.length); - map = nmap; - low = nlow; - map[i - low] = value; - } - - private void growForward(int i, T value) { - int nlen = i - low + 1 + EXTRA; - Object[] nmap = new Object[nlen]; - System.arraycopy(map, 0, nmap, 0, map.length); - map = nmap; - map[i - low] = value; - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BitMap2D.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import java.util.*; - -/** - * This class implements a two-dimensional bitmap. - */ -public final class BitMap2D { - - private BitSet map; - private final int bitsPerSlot; - - private int bitIndex(int slotIndex, int bitWithinSlotIndex) { - return slotIndex * bitsPerSlot + bitWithinSlotIndex; - } - - private boolean verifyBitWithinSlotIndex(int index) { - assert index < bitsPerSlot : "index " + index + " is out of bounds " + bitsPerSlot; - return true; - } - - public BitMap2D(int sizeInSlots, int bitsPerSlot) { - map = new BitSet(sizeInSlots * bitsPerSlot); - this.bitsPerSlot = bitsPerSlot; - } - - public int sizeInBits() { - return map.size(); - } - - // Returns number of full slots that have been allocated - public int sizeInSlots() { - return map.size() / bitsPerSlot; - } - - public boolean isValidIndex(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - return (bitIndex(slotIndex, bitWithinSlotIndex) < sizeInBits()); - } - - public boolean at(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - return map.get(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void setBit(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - map.set(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void clearBit(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - map.clear(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void atPutGrow(int slotIndex, int bitWithinSlotIndex, boolean value) { - int size = sizeInSlots(); - if (size <= slotIndex) { - while (size <= slotIndex) { - size *= 2; - } - BitSet newBitMap = new BitSet(size * bitsPerSlot); - newBitMap.or(map); - map = newBitMap; - } - - if (value) { - setBit(slotIndex, bitWithinSlotIndex); - } else { - clearBit(slotIndex, bitWithinSlotIndex); - } - } - - public void clear() { - map.clear(); - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BlockWorkList.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import com.oracle.graal.nodes.*; - -/** - * This class implements a worklist for dealing with blocks. The worklist can - * operate either as a stack (i.e. first-in / last-out), or as a sorted list, - * where blocks can be sorted by a supplied number. The latter usage lends itself - * naturally to iterative dataflow analysis problems. - */ -public class BlockWorkList { - MergeNode[] workList; - int[] workListNumbers; - int workListIndex; - - /** - * Adds a block to this list in an unsorted fashion, like a stack. - * @param block the block to add - */ - public void add(MergeNode block) { - if (workList == null) { - // worklist not allocated yet - allocate(); - } else if (workListIndex == workList.length) { - // need to grow the worklist - grow(); - } - // put the block at the end of the array - workList[workListIndex++] = block; - } - - /** - * Adds a block to this list, sorted by the supplied number. The block - * with the lowest number is returned upon subsequent removes. - * @param block the block to add - * @param number the number used to sort the block - */ - public void addSorted(MergeNode block, int number) { - if (workList == null) { - // worklist not allocated yet - allocate(); - } else if (workListIndex == workList.length) { - // need to grow the worklist - grow(); - } - // put the block at the end of the array - workList[workListIndex] = block; - workListNumbers[workListIndex] = number; - workListIndex++; - int i = workListIndex - 2; - // push block towards the beginning of the array - for (; i >= 0; i--) { - int n = workListNumbers[i]; - if (n >= number) { - break; // already in the right position - } - workList[i + 1] = workList[i]; // bubble b down by one - workList[i] = block; // and overwrite its place with block - workListNumbers[i + 1] = n; // bubble n down by one - workListNumbers[i] = number; // and overwrite its place with number - } - } - - /** - * Removes the next block from this work list. If the blocks have been added - * in a sorted order, then the block with the lowest number is returned. Otherwise, - * the last block added is returned. - * @return the next block in the list - */ - public MergeNode removeFromWorkList() { - if (workListIndex != 0) { - return workList[--workListIndex]; - } - return null; - } - - /** - * Checks whether the list is empty. - * @return {@code true} if this list is empty - */ - public boolean isEmpty() { - return workListIndex == 0; - } - - private void allocate() { - workList = new MergeNode[5]; - workListNumbers = new int[5]; - } - - private void grow() { - int prevLength = workList.length; - MergeNode[] nworkList = new MergeNode[prevLength * 3]; - System.arraycopy(workList, 0, nworkList, 0, prevLength); - workList = nworkList; - - int[] nworkListNumbers = new int[prevLength * 3]; - System.arraycopy(workListNumbers, 0, nworkListNumbers, 0, prevLength); - workListNumbers = nworkListNumbers; - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/GraphOrder.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -public class GraphOrder implements Iterable<Node> { - - private final ArrayList<Node> nodes = new ArrayList<>(); - - private GraphOrder() { - } - - public GraphOrder(Graph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - - for (ReturnNode node : graph.getNodes(ReturnNode.class)) { - visitForward(visited, node); - } - for (UnwindNode node : graph.getNodes(UnwindNode.class)) { - visitForward(visited, node); - } - for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { - visitForward(visited, node); - } - } - - public static GraphOrder forwardGraph(Graph graph) { - GraphOrder result = new GraphOrder(); - - NodeBitMap visited = graph.createNodeBitMap(); - - for (ReturnNode node : graph.getNodes(ReturnNode.class)) { - result.visitForward(visited, node); - } - for (UnwindNode node : graph.getNodes(UnwindNode.class)) { - result.visitForward(visited, node); - } - for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { - result.visitForward(visited, node); - } - return result; - } - - public static GraphOrder backwardGraph(Graph graph) { - GraphOrder result = new GraphOrder(); - - NodeBitMap visited = graph.createNodeBitMap(); - - for (Node node : forwardGraph(graph)) { - result.visitBackward(visited, node); - } - return result; - } - - private void visitForward(NodeBitMap visited, Node node) { - if (node != null && !visited.isMarked(node)) { - visited.mark(node); - if (node.predecessor() != null) { - visitForward(visited, node.predecessor()); - } - if (node instanceof MergeNode) { - // make sure that the cfg predecessors of a MergeNode are processed first - MergeNode merge = (MergeNode) node; - for (int i = 0; i < merge.forwardEndCount(); i++) { - visitForward(visited, merge.forwardEndAt(i)); - } - } - for (Node input : node.inputs()) { - visitForward(visited, input); - } - nodes.add(node); - } - } - - private void visitBackward(NodeBitMap visited, Node node) { - if (node != null && !visited.isMarked(node)) { - visited.mark(node); - for (Node successor : node.successors()) { - visitBackward(visited, successor); - } - for (Node usage : node.usages()) { - visitBackward(visited, usage); - } - nodes.add(node); - } - } - - @Override - public Iterator<Node> iterator() { - return new Iterator<Node>() { - - private int pos = 0; - - private void removeDeleted() { - while (pos < nodes.size() && nodes.get(pos).isDeleted()) { - pos++; - } - } - - @Override - public boolean hasNext() { - removeDeleted(); - return pos < nodes.size(); - } - - @Override - public Node next() { - return nodes.get(pos++); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/InliningUtil.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,960 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.JavaType.Representation; -import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.FrameState.InliningIdentifier; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -public class InliningUtil { - - private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication"); - - public interface InliningCallback { - StructuredGraph buildGraph(ResolvedJavaMethod method); - double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke); - void recordMethodContentsAssumption(ResolvedJavaMethod method); - void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl); - } - - public static String methodName(ResolvedJavaMethod method, Invoke invoke) { - if (!Debug.isLogEnabled()) { - return null; - } else if (invoke != null && invoke.stateAfter() != null) { - return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; - } else { - return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; - } - } - - public static String methodName(InlineInfo info) { - if (!Debug.isLogEnabled()) { - return null; - } else if (info.invoke != null && info.invoke.stateAfter() != null) { - return methodName(info.invoke.stateAfter(), info.invoke.bci()) + ": " + info.toString(); - } else { - return info.toString(); - } - } - - private static String methodName(FrameState frameState, int bci) { - StringBuilder sb = new StringBuilder(); - if (frameState.outerFrameState() != null) { - sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci)); - sb.append("->"); - } - sb.append(MetaUtil.format("%h.%n", frameState.method())); - sb.append("@").append(bci); - return sb.toString(); - } - - /** - * Represents an opportunity for inlining at the given invoke, with the given weight and level. - * The weight is the amortized weight of the additional code - so smaller is better. - * The level is the number of nested inlinings that lead to this invoke. - */ - public abstract static class InlineInfo implements Comparable<InlineInfo> { - public final Invoke invoke; - public final double weight; - public final int level; - - public InlineInfo(Invoke invoke, double weight, int level) { - this.invoke = invoke; - this.weight = weight; - this.level = level; - } - - public abstract int compiledCodeSize(); - - @Override - public int compareTo(InlineInfo o) { - return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0; - } - - protected static StructuredGraph getGraph(final ResolvedJavaMethod concrete, final InliningCallback callback) { - return Debug.scope("GetInliningGraph", concrete, new Callable<StructuredGraph>() { - @Override - public StructuredGraph call() throws Exception { - return callback.buildGraph(concrete); - } - }); - } - - public abstract boolean canDeopt(); - - /** - * Performs the inlining described by this object and returns the node that represents the return value of the - * inlined method (or null for void methods and methods that have no non-exceptional exit). - * - * @param graph - * @param runtime - * @param callback - */ - public abstract void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback); - } - - /** - * Represents an inlining opportunity where the compiler can statically determine a monomorphic target method and - * therefore is able to determine the called method exactly. - */ - private static class ExactInlineInfo extends InlineInfo { - public final ResolvedJavaMethod concrete; - - public ExactInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete) { - super(invoke, weight, level); - this.concrete = concrete; - } - - @Override - public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, final InliningCallback callback) { - StructuredGraph graph = getGraph(concrete, callback); - assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); - callback.recordMethodContentsAssumption(concrete); - InliningUtil.inline(invoke, graph, true); - } - - @Override - public int compiledCodeSize() { - return concrete.compiledCodeSize(); - } - - @Override - public String toString() { - return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete); - } - - @Override - public boolean canDeopt() { - return false; - } - } - - /** - * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which - * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed. - */ - private static class TypeGuardInlineInfo extends InlineInfo { - public final ResolvedJavaMethod concrete; - public final ResolvedJavaType type; - - public TypeGuardInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete, ResolvedJavaType type) { - super(invoke, weight, level); - this.concrete = concrete; - this.type = type; - } - - @Override - public int compiledCodeSize() { - return concrete.compiledCodeSize(); - } - - @Override - public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - // receiver null check must be before the type check - InliningUtil.receiverNullCheck(invoke); - ValueNode receiver = invoke.methodCallTarget().receiver(); - LoadHubNode receiverHub = graph.add(new LoadHubNode(receiver)); - ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), runtime, graph); - ObjectEqualsNode typeCheck = graph.unique(new ObjectEqualsNode(receiverHub, typeHub)); - FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, invoke.leafGraphId())); - ValueAnchorNode anchor = graph.add(new ValueAnchorNode()); - assert invoke.predecessor() != null; - - ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true); - invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver); - - graph.addBeforeFixed(invoke.node(), receiverHub); - graph.addBeforeFixed(invoke.node(), guard); - graph.addBeforeFixed(invoke.node(), anchor); - - StructuredGraph calleeGraph = getGraph(concrete, callback); - assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); - callback.recordMethodContentsAssumption(concrete); - InliningUtil.inline(invoke, calleeGraph, false); - } - - @Override - public String toString() { - return "type-checked " + MetaUtil.format("%H.%n(%p):%r", concrete); - } - - @Override - public boolean canDeopt() { - return true; - } - } - - /** - * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable - * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered. - */ - private static class MultiTypeGuardInlineInfo extends InlineInfo { - public final List<ResolvedJavaMethod> concretes; - public final ProfiledType[] ptypes; - public final int[] typesToConcretes; - public final double notRecordedTypeProbability; - - public MultiTypeGuardInlineInfo(Invoke invoke, double weight, int level, List<ResolvedJavaMethod> concretes, ProfiledType[] ptypes, - int[] typesToConcretes, double notRecordedTypeProbability) { - super(invoke, weight, level); - assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods"; - assert ptypes.length == typesToConcretes.length : "array lengths must match"; - - this.concretes = concretes; - this.ptypes = ptypes; - this.typesToConcretes = typesToConcretes; - this.notRecordedTypeProbability = notRecordedTypeProbability; - } - - @Override - public int compiledCodeSize() { - int result = 0; - for (ResolvedJavaMethod m: concretes) { - result += m.compiledCodeSize(); - } - return result; - } - - @Override - public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - int numberOfMethods = concretes.size(); - boolean hasReturnValue = invoke.node().kind() != Kind.Void; - - // receiver null check must be the first node - InliningUtil.receiverNullCheck(invoke); - if (numberOfMethods > 1 || shouldFallbackToInvoke()) { - inlineMultipleMethods(graph, runtime, callback, numberOfMethods, hasReturnValue); - } else { - inlineSingleMethod(graph, runtime, callback); - } - } - - private boolean shouldFallbackToInvoke() { - return notRecordedTypeProbability > 0; - } - - private void inlineMultipleMethods(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, int numberOfMethods, boolean hasReturnValue) { - FixedNode continuation = invoke.next(); - - ValueNode originalReceiver = invoke.methodCallTarget().receiver(); - // setup merge and phi nodes for results and exceptions - MergeNode returnMerge = graph.add(new MergeNode()); - returnMerge.setProbability(invoke.probability()); - returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci)); - - PhiNode returnValuePhi = null; - if (hasReturnValue) { - returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge)); - } - - MergeNode exceptionMerge = null; - PhiNode exceptionObjectPhi = null; - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; - DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge(); - ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); - - exceptionMerge = graph.add(new MergeNode()); - exceptionMerge.setProbability(exceptionEdge.probability()); - - FixedNode exceptionSux = exceptionObject.next(); - graph.addBeforeFixed(exceptionSux, exceptionMerge); - exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge)); - exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Void, exceptionObjectPhi)); - } - - // create one separate block for each invoked method - BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods]; - for (int i = 0; i < numberOfMethods; i++) { - int predecessors = 0; - double probability = 0; - for (int j = 0; j < typesToConcretes.length; j++) { - if (typesToConcretes[j] == i) { - predecessors++; - probability += ptypes[j].probability; - } - } - - calleeEntryNodes[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, predecessors, invoke.probability() * probability, true); - } - - // create the successor for an unknown type - FixedNode unknownTypeNode; - if (shouldFallbackToInvoke()) { - unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, notRecordedTypeProbability, false); - } else { - unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())); - } - - // replace the invoke exception edge - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke; - BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge(); - ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); - exceptionObject.replaceAtUsages(exceptionObjectPhi); - exceptionObject.setNext(null); - GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge()); - } - - // replace the invoke with a switch on the type of the actual receiver - LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver())); - graph.addBeforeFixed(invoke.node(), receiverHub); - FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, calleeEntryNodes, unknownTypeNode); - - assert invoke.next() == continuation; - invoke.setNext(null); - returnMerge.setNext(continuation); - invoke.node().replaceAtUsages(returnValuePhi); - invoke.node().replaceAndDelete(dispatchOnType); - - ArrayList<PiNode> replacements = new ArrayList<>(); - - // do the actual inlining for every invoke - for (int i = 0; i < calleeEntryNodes.length; i++) { - BeginNode node = calleeEntryNodes[i]; - Invoke invokeForInlining = (Invoke) node.next(); - - ResolvedJavaType commonType = getLeastCommonType(i); - ValueNode receiver = invokeForInlining.methodCallTarget().receiver(); - boolean exact = getTypeCount(i) == 1; - PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact); - invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver); - - ResolvedJavaMethod concrete = concretes.get(i); - StructuredGraph calleeGraph = getGraph(concrete, callback); - callback.recordMethodContentsAssumption(concrete); - assert !IntrinsificationPhase.canIntrinsify(invokeForInlining, concrete, runtime); - InliningUtil.inline(invokeForInlining, calleeGraph, false); - replacements.add(anchoredReceiver); - } - if (shouldFallbackToInvoke()) { - replacements.add(null); - } - if (GraalOptions.OptTailDuplication) { - /* - * 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).methodCallTarget().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); - TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements); - } - } - } - - private int getTypeCount(int concreteMethodIndex) { - int count = 0; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { - count++; - } - } - return count; - } - - private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) { - ResolvedJavaType commonType = null; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { - if (commonType == null) { - commonType = ptypes[i].type; - } else { - commonType = commonType.leastCommonAncestor(ptypes[i].type); - } - } - } - assert commonType != null; - return commonType; - } - - private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; - - MergeNode calleeEntryNode = graph.add(new MergeNode()); - calleeEntryNode.setProbability(invoke.probability()); - LoadHubNode receiverHub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver())); - graph.addBeforeFixed(invoke.node(), receiverHub); - - FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())); - FixedNode dispatchOnType = createDispatchOnType(graph, receiverHub, new BeginNode[] {calleeEntryNode}, unknownTypeNode); - - FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor(); - pred.setNext(dispatchOnType); - calleeEntryNode.setNext(invoke.node()); - - ResolvedJavaMethod concrete = concretes.get(0); - StructuredGraph calleeGraph = getGraph(concrete, callback); - assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); - callback.recordMethodContentsAssumption(concrete); - InliningUtil.inline(invoke, calleeGraph, false); - } - - private FixedNode createDispatchOnType(StructuredGraph graph, LoadHubNode objectClassNode, BeginNode[] calleeEntryNodes, FixedNode unknownTypeSux) { - assert ptypes.length > 1; - - ResolvedJavaType[] types = new ResolvedJavaType[ptypes.length]; - double[] probabilities = new double[ptypes.length + 1]; - BeginNode[] successors = new BeginNode[ptypes.length + 1]; - int[] keySuccessors = new int[ptypes.length + 1]; - for (int i = 0; i < ptypes.length; i++) { - types[i] = ptypes[i].type; - probabilities[i] = ptypes[i].probability; - FixedNode entry = calleeEntryNodes[typesToConcretes[i]]; - if (entry instanceof MergeNode) { - EndNode endNode = graph.add(new EndNode()); - ((MergeNode) entry).addForwardEnd(endNode); - entry = endNode; - } - successors[i] = BeginNode.begin(entry); - keySuccessors[i] = i; - } - assert !(unknownTypeSux instanceof MergeNode); - successors[successors.length - 1] = BeginNode.begin(unknownTypeSux); - probabilities[successors.length - 1] = notRecordedTypeProbability; - keySuccessors[successors.length - 1] = successors.length - 1; - - TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(objectClassNode, successors, probabilities, types, probabilities, keySuccessors)); - - return typeSwitch; - } - - private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, - MergeNode exceptionMerge, PhiNode exceptionObjectPhi, int predecessors, double probability, boolean useForInlining) { - Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability); - BeginNode calleeEntryNode = graph.add(predecessors > 1 ? new MergeNode() : new BeginNode()); - calleeEntryNode.setNext(duplicatedInvoke.node()); - calleeEntryNode.setProbability(probability); - - EndNode endNode = graph.add(new EndNode()); - endNode.setProbability(probability); - - duplicatedInvoke.setNext(endNode); - returnMerge.addForwardEnd(endNode); - - if (returnValuePhi != null) { - returnValuePhi.addInput(duplicatedInvoke.node()); - } - return calleeEntryNode; - } - - private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) { - Invoke result = (Invoke) invoke.node().copyWithInputs(); - Node callTarget = result.callTarget().copyWithInputs(); - result.node().replaceFirstInput(result.callTarget(), callTarget); - result.setUseForInlining(useForInlining); - result.setProbability(probability); - - Kind kind = invoke.node().kind(); - if (!kind.isVoid()) { - FrameState stateAfter = invoke.stateAfter(); - stateAfter = stateAfter.duplicate(stateAfter.bci); - stateAfter.replaceFirstInput(invoke.node(), result.node()); - result.setStateAfter(stateAfter); - } - - if (invoke instanceof InvokeWithExceptionNode) { - assert exceptionMerge != null && exceptionObjectPhi != null; - - InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; - BeginNode exceptionEdge = invokeWithException.exceptionEdge(); - ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); - FrameState stateAfterException = exceptionObject.stateAfter(); - - BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs(); - ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs(); - // set new state (pop old exception object, push new one) - newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject)); - newExceptionEdge.setNext(newExceptionObject); - - EndNode endNode = graph.add(new EndNode()); - newExceptionObject.setNext(endNode); - exceptionMerge.addForwardEnd(endNode); - exceptionObjectPhi.addInput(newExceptionObject); - - ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge); - } - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic"); - builder.append(String.format(", %d methods with %d type checks:", concretes.size(), ptypes.length)); - for (int i = 0; i < concretes.size(); i++) { - builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i))); - } - return builder.toString(); - } - - @Override - public boolean canDeopt() { - return true; - } - } - - - /** - * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method, - * but for which an assumption has to be registered because of non-final classes. - */ - private static class AssumptionInlineInfo extends ExactInlineInfo { - public final ResolvedJavaType context; - - public AssumptionInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaType context, ResolvedJavaMethod concrete) { - super(invoke, weight, level, concrete); - this.context = context; - } - - @Override - public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - if (Debug.isLogEnabled()) { - String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod()); - String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete); - Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName); - } - callback.recordConcreteMethodAssumption(invoke.methodCallTarget().targetMethod(), context, concrete); - - super.inline(graph, runtime, callback); - } - - @Override - public String toString() { - return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete); - } - - @Override - public boolean canDeopt() { - return true; - } - } - - /** - * Determines if inlining is possible at the given invoke node. - * @param invoke the invoke that should be inlined - * @param level the number of nested inlinings that lead to this invoke, or 0 if the invoke was part of the initial graph - * @param runtime a GraalRuntime instance used to determine of the invoke can be inlined and/or should be intrinsified - * @param callback a callback that is used to determine the weight of a specific inlining - * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke - */ - public static InlineInfo getInlineInfo(Invoke invoke, int level, GraalCodeCacheProvider runtime, Assumptions assumptions, InliningCallback callback, OptimisticOptimizations optimisticOpts) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { - // The invoke has already been lowered , or has been created as a low-level node. We have no method information. - return null; - } - ResolvedJavaMethod parent = invoke.stateAfter().method(); - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (targetMethod == null) { - return null; - } - if (!checkInvokeConditions(invoke)) { - return null; - } - - if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) { - if (checkTargetConditions(invoke, targetMethod, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, targetMethod, invoke); - return new ExactInlineInfo(invoke, weight, level, targetMethod); - } - return null; - } - ObjectStamp receiverStamp = callTarget.receiver().objectStamp(); - ResolvedJavaType receiverType = receiverStamp.type(); - if (receiverStamp.isExactType()) { - assert receiverType.isSubtypeOf(targetMethod.holder()) : receiverType + " subtype of " + targetMethod.holder() + " for " + targetMethod; - ResolvedJavaMethod resolved = receiverType.resolveMethodImpl(targetMethod); - if (checkTargetConditions(invoke, resolved, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, resolved, invoke); - return new ExactInlineInfo(invoke, weight, level, resolved); - } - return null; - } - ResolvedJavaType holder = targetMethod.holder(); - - if (receiverStamp.type() != null) { - // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...) - // TODO (lstadler) fix this - if (receiverType != null && receiverType.isSubtypeOf(holder)) { - holder = receiverType; - } - } - // TODO (thomaswue) fix this - if (assumptions != null) { - ResolvedJavaMethod concrete = holder.uniqueConcreteMethod(targetMethod); - if (concrete != null) { - if (checkTargetConditions(invoke, concrete, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - return new AssumptionInlineInfo(invoke, weight, level, holder, concrete); - } - return null; - } - } - - // type check based inlining - return getTypeCheckedInlineInfo(invoke, level, callback, parent, targetMethod, optimisticOpts); - } - - private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, int level, InliningCallback callback, ResolvedJavaMethod parent, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) { - ProfilingInfo profilingInfo = parent.profilingInfo(); - JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); - if (typeProfile != null) { - ProfiledType[] ptypes = typeProfile.getTypes(); - - if (ptypes != null && ptypes.length > 0) { - double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); - if (ptypes.length == 1 && notRecordedTypeProbability == 0) { - if (optimisticOpts.inlineMonomorphicCalls()) { - ResolvedJavaType type = ptypes[0].type; - ResolvedJavaMethod concrete = type.resolveMethodImpl(targetMethod); - if (checkTargetConditions(invoke, concrete, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - return new TypeGuardInlineInfo(invoke, weight, level, concrete, type); - } - - Debug.log("not inlining %s because method can't be inlined", methodName(targetMethod, invoke)); - return null; - } else { - Debug.log("not inlining %s because GraalOptions.InlineMonomorphicCalls == false", methodName(targetMethod, invoke)); - return null; - } - } else { - invoke.setMegamorphic(true); - if (optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0 || optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { - // TODO (chaeubl) inlining of multiple methods should work differently - // 1. check which methods can be inlined - // 2. for those methods, use weight and probability to compute which of them should be inlined - // 3. do the inlining - // a) all seen methods can be inlined -> do so and guard with deopt - // b) some methods can be inlined -> inline them and fall back to invocation if violated - // TODO (chaeubl) sort types by probability - - // determine concrete methods and map type to specific method - ArrayList<ResolvedJavaMethod> concreteMethods = new ArrayList<>(); - int[] typesToConcretes = new int[ptypes.length]; - for (int i = 0; i < ptypes.length; i++) { - ResolvedJavaMethod concrete = ptypes[i].type.resolveMethodImpl(targetMethod); - - int index = concreteMethods.indexOf(concrete); - if (index < 0) { - index = concreteMethods.size(); - concreteMethods.add(concrete); - } - typesToConcretes[i] = index; - } - - double totalWeight = 0; - boolean canInline = true; - for (ResolvedJavaMethod concrete: concreteMethods) { - if (!checkTargetConditions(invoke, concrete, optimisticOpts)) { - canInline = false; - break; - } - totalWeight += callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - } - - if (canInline) { - return new MultiTypeGuardInlineInfo(invoke, totalWeight, level, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability); - } else { - Debug.log("not inlining %s because it is a polymorphic method call and at least one invoked method cannot be inlined", methodName(targetMethod, invoke)); - return null; - } - } else { - if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { - Debug.log("not inlining %s because GraalOptions.InlinePolymorphicCalls == false", methodName(targetMethod, invoke)); - } else { - Debug.log("not inlining %s because GraalOptions.InlineMegamorphicCalls == false", methodName(targetMethod, invoke)); - } - return null; - } - } - } - - Debug.log("not inlining %s because no types/probabilities were recorded", methodName(targetMethod, invoke)); - return null; - } else { - Debug.log("not inlining %s because no type profile exists", methodName(targetMethod, invoke)); - return null; - } - } - - private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { - // to avoid that floating reads on receiver fields float above the type check - return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType))); - } - - private static boolean checkInvokeConditions(Invoke invoke) { - if (invoke.stateAfter() == null) { - Debug.log("not inlining %s because the invoke has no after state", methodName(invoke.methodCallTarget().targetMethod(), invoke)); - return false; - } - if (invoke.predecessor() == null) { - Debug.log("not inlining %s because the invoke is dead code", methodName(invoke.methodCallTarget().targetMethod(), invoke)); - return false; - } - if (!invoke.useForInlining()) { - Debug.log("not inlining %s because invoke is marked to be not used for inlining", methodName(invoke.methodCallTarget().targetMethod(), invoke)); - return false; - } - return true; - } - - private static boolean checkTargetConditions(Invoke invoke, JavaMethod method, OptimisticOptimizations optimisticOpts) { - if (method == null) { - Debug.log("not inlining because method is not resolved"); - return false; - } - if (!(method instanceof ResolvedJavaMethod)) { - Debug.log("not inlining %s because it is unresolved", method.toString()); - return false; - } - ResolvedJavaMethod resolvedMethod = (ResolvedJavaMethod) method; - if (Modifier.isNative(resolvedMethod.accessFlags())) { - Debug.log("not inlining %s because it is a native method", methodName(resolvedMethod, invoke)); - return false; - } - if (Modifier.isAbstract(resolvedMethod.accessFlags())) { - Debug.log("not inlining %s because it is an abstract method", methodName(resolvedMethod, invoke)); - return false; - } - if (!resolvedMethod.holder().isInitialized()) { - Debug.log("not inlining %s because of non-initialized class", methodName(resolvedMethod, invoke)); - return false; - } - if (!resolvedMethod.canBeInlined()) { - Debug.log("not inlining %s because it is marked non-inlinable", methodName(resolvedMethod, invoke)); - return false; - } - if (computeRecursiveInliningLevel(invoke.stateAfter(), (ResolvedJavaMethod) method) > GraalOptions.MaximumRecursiveInlining) { - Debug.log("not inlining %s because it exceeds the maximum recursive inlining depth", methodName(resolvedMethod, invoke)); - return false; - } - OptimisticOptimizations calleeOpts = new OptimisticOptimizations(resolvedMethod); - if (calleeOpts.lessOptimisticThan(optimisticOpts)) { - Debug.log("not inlining %s because callee uses less optimistic optimizations than caller", methodName(resolvedMethod, invoke)); - return false; - } - - return true; - } - - private static int computeRecursiveInliningLevel(FrameState state, ResolvedJavaMethod method) { - assert state != null; - - int count = 0; - FrameState curState = state; - while (curState != null) { - if (curState.method() == method) { - count++; - } - curState = curState.outerFrameState(); - } - return count; - } - - /** - * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. - * - * @param invoke the invoke that will be replaced - * @param inlineGraph the graph that the invoke will be replaced with - * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required - */ - public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { - InliningIdentifier identifier = new InliningIdentifier(inlineGraph.method(), invoke); - NodeInputList<ValueNode> parameters = invoke.callTarget().arguments(); - StructuredGraph graph = (StructuredGraph) invoke.node().graph(); - - FrameState stateAfter = invoke.stateAfter(); - assert stateAfter.isAlive(); - - IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>(); - ArrayList<Node> nodes = new ArrayList<>(); - ReturnNode returnNode = null; - UnwindNode unwindNode = null; - StartNode entryPointNode = inlineGraph.start(); - FixedNode firstCFGNode = entryPointNode.next(); - for (Node node : inlineGraph.getNodes()) { - if (node == entryPointNode || node == entryPointNode.stateAfter()) { - // Do nothing. - } else if (node instanceof LocalNode) { - replacements.put(node, parameters.get(((LocalNode) node).index())); - } else { - nodes.add(node); - if (node instanceof ReturnNode) { - assert returnNode == null; - returnNode = (ReturnNode) node; - } else if (node instanceof UnwindNode) { - assert unwindNode == null; - unwindNode = (UnwindNode) node; - } - } - } - replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode - - assert invoke.node().successors().first() != null : invoke; - assert invoke.node().predecessor() != null; - - Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements); - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - if (receiverNullCheck) { - receiverNullCheck(invoke); - } - invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate); - - FrameState stateAtExceptionEdge = null; - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); - if (unwindNode != null) { - assert unwindNode.predecessor() != null; - assert invokeWithException.exceptionEdge().successors().count() == 1; - ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next(); - stateAtExceptionEdge = obj.stateAfter(); - UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); - obj.replaceAtUsages(unwindDuplicate.exception()); - unwindDuplicate.clearInputs(); - Node n = obj.next(); - obj.setNext(null); - unwindDuplicate.replaceAndDelete(n); - } else { - invokeWithException.killExceptionEdge(); - } - } else { - if (unwindNode != null) { - UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); - DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler, invoke.leafGraphId()); - unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode)); - // move the deopt upwards if there is a monitor exit that tries to use the "after exception" frame state - // (because there is no "after exception" frame state!) - if (deoptimizeNode.predecessor() instanceof MonitorExitNode) { - MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor(); - if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) { - FrameState monitorFrameState = monitorExit.stateAfter(); - graph.removeFixed(monitorExit); - monitorFrameState.safeDelete(); - } - } - } - } - - FrameState outerFrameState = null; - double invokeProbability = invoke.node().probability(); - for (Node node : duplicates.values()) { - if (GraalOptions.ProbabilityAnalysis) { - if (node instanceof FixedNode) { - FixedNode fixed = (FixedNode) node; - double newProbability = fixed.probability() * invokeProbability; - if (GraalOptions.LimitInlinedProbability) { - newProbability = Math.min(newProbability, invokeProbability); - } - fixed.setProbability(newProbability); - } - } - if (node instanceof FrameState) { - FrameState frameState = (FrameState) node; - assert frameState.bci != FrameState.BEFORE_BCI; - if (frameState.bci == FrameState.AFTER_BCI) { - frameState.replaceAndDelete(stateAfter); - } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) { - if (frameState.isAlive()) { - assert stateAtExceptionEdge != null; - frameState.replaceAndDelete(stateAtExceptionEdge); - } else { - assert stateAtExceptionEdge == null; - } - } else { - // only handle the outermost frame states - if (frameState.outerFrameState() == null) { - assert frameState.method() == inlineGraph.method(); - if (outerFrameState == null) { - outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind()); - outerFrameState.setDuringCall(true); - } - frameState.setOuterFrameState(outerFrameState); - frameState.setInliningIdentifier(identifier); - } - } - } - } - - Node returnValue = null; - if (returnNode != null) { - if (returnNode.result() instanceof LocalNode) { - returnValue = replacements.get(returnNode.result()); - } else { - returnValue = duplicates.get(returnNode.result()); - } - invoke.node().replaceAtUsages(returnValue); - Node returnDuplicate = duplicates.get(returnNode); - returnDuplicate.clearInputs(); - Node n = invoke.next(); - invoke.setNext(null); - returnDuplicate.replaceAndDelete(n); - } - - invoke.node().clearInputs(); - invoke.node().replaceAtUsages(null); - GraphUtil.killCFG(invoke.node()); - - if (stateAfter.usages().isEmpty()) { - stateAfter.safeDelete(); - } - } - - public static void receiverNullCheck(Invoke invoke) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - StructuredGraph graph = (StructuredGraph) invoke.graph(); - NodeInputList<ValueNode> parameters = callTarget.arguments(); - ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0); - if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) { - graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, true, invoke.leafGraphId()))); - } - } -}
--- a/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/IntList.java Fri Oct 05 17:55:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import java.util.*; - -/** - * An expandable and indexable list of {@code int}s. - * - * This class avoids the boxing/unboxing incurred by {@code ArrayList<Integer>}. - */ -public final class IntList { - - private int[] array; - private int size; - - /** - * Creates an int list with a specified initial capacity. - * - * @param initialCapacity - */ - public IntList(int initialCapacity) { - array = new int[initialCapacity]; - } - - /** - * Creates an int list with a specified initial array. - * - * @param array the initial array used for the list (no copy is made) - * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or equal to {@code array.length} - */ - public IntList(int[] array, int initialSize) { - assert initialSize <= array.length; - this.array = array; - this.size = initialSize; - } -