# HG changeset patch # User Lukas Stadler # Date 1334922246 -7200 # Node ID c9dd4054c23b0fde0ef302a7b3e1af2d28ef618d # Parent b8661be84cfd3315e333d8b6c0bd655368871e8b# Parent d87155082c4de7e6143eded9b3b2cfe824e7f478 Merge diff -r d87155082c4d -r c9dd4054c23b .hgignore --- a/.hgignore Fri Apr 13 15:52:25 2012 +0200 +++ b/.hgignore Fri Apr 20 13:44:06 2012 +0200 @@ -1,4 +1,6 @@ ^mx/env +^mx/checkstyle-timestamps +^mx/eclipse-launches ^mx/ecj.jar ^mx/includes ^build/ @@ -9,7 +11,6 @@ ^java64/ ^work/ \.checkstyle$ -\.checkstyle.*.timestamp \.classpath \.project \.settings/ diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Fri Apr 20 13:44:06 2012 +0200 @@ -41,7 +41,6 @@ import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; -import com.oracle.max.asm.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.cri.xir.*; @@ -128,46 +127,38 @@ new PhiStampPhase().apply(graph); + if (GraalOptions.ProbabilityAnalysis && graph.start().probability() == 0) { + new ComputeProbabilityPhase().apply(graph); + } + + if (GraalOptions.PropagateTypes) { + new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); + } + if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase(target, runtime, assumptions).apply(graph); } - if (GraalOptions.ProbabilityAnalysis && graph.start().probability() == 0) { - new ComputeProbabilityPhase().apply(graph); - } - if (GraalOptions.Intrinsify) { new IntrinsificationPhase(runtime).apply(graph); } - if (GraalOptions.PropagateTypes) { - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } - - new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); - } - if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) { new InliningPhase(target, runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph); new DeadCodeEliminationPhase().apply(graph); new PhiStampPhase().apply(graph); - } + if (GraalOptions.PropagateTypes) { + new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); + } - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } } - if (GraalOptions.PropagateTypes) { - new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); - } plan.runPhases(PhasePosition.HIGH_LEVEL, graph); - if (GraalOptions.OptLoops) { - new SafepointPollingEliminationPhase().apply(graph); - } - if (GraalOptions.EscapeAnalysis && !plan.isPhaseDisabled(EscapeAnalysisPhase.class)) { new EscapeAnalysisPhase(target, runtime, assumptions, cache, plan, optimisticOpts).apply(graph); new PhiStampPhase().apply(graph); @@ -175,7 +166,18 @@ new CanonicalizerPhase(target, runtime, assumptions).apply(graph); } } - + if (GraalOptions.OptLoops) { + if (GraalOptions.OptLoopTransform) { + new LoopTransformPhase().apply(graph); + } + if (GraalOptions.OptSafepointElimination) { + new SafepointPollingEliminationPhase().apply(graph); + } + } + new RemoveValueProxyPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } if (GraalOptions.OptGVN) { new GlobalValueNumberingPhase().apply(graph); } @@ -197,6 +199,9 @@ if (GraalOptions.PropagateTypes) { new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); } + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } if (GraalOptions.OptGVN) { new GlobalValueNumberingPhase().apply(graph); } @@ -228,7 +233,7 @@ b.linearScanNumber = z++; } - LIR lir = new LIR(schedule.getCFG(), schedule.getNodesFor(), linearScanOrder, codeEmittingOrder); + LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder); Debug.dump(lir, "After linear scan order"); return lir; @@ -263,24 +268,14 @@ return frameMap; } - private TargetMethodAssembler createAssembler(FrameMap frameMap, LIR lir) { - AbstractAssembler masm = backend.newAssembler(frameMap.registerConfig); - TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime, frameMap, lir.slowPaths, masm); - tasm.setFrameSize(frameMap.frameSize()); - tasm.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea()); - return tasm; - } - public CiTargetMethod emitCode(CiAssumptions assumptions, RiResolvedMethod method, LIR lir, FrameMap frameMap) { - TargetMethodAssembler tasm = createAssembler(frameMap, lir); - lir.emitCode(tasm); - + TargetMethodAssembler tasm = backend.newAssembler(frameMap, lir); + backend.emitCode(tasm, method, lir); CiTargetMethod targetMethod = tasm.finishTargetMethod(method, false); if (assumptions != null && !assumptions.isEmpty()) { targetMethod.setAssumptions(assumptions); } - Debug.dump(lir, "After code generation"); Debug.dump(targetMethod, "After code generation"); return targetMethod; } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Fri Apr 20 13:44:06 2012 +0200 @@ -98,6 +98,9 @@ //rematerialize settings public static float MinimumUsageProbability = 0.95f; + //loop transform settings + public static float MinimumPeelProbability = 0.25f; + // debugging settings public static int MethodEndBreakpointGuards = 0; public static boolean ZapStackOnMethodEntry = ____; @@ -143,6 +146,7 @@ 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; @@ -192,12 +196,14 @@ public static boolean OptReadElimination = true; public static boolean OptGVN = true; public static boolean OptCanonicalizer = true; - public static boolean OptLoops = ____; + public static boolean OptLoops = 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; /** * Flag to turn on SSA-based register allocation, which is currently under development. diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Fri Apr 20 13:44:06 2012 +0200 @@ -846,7 +846,7 @@ TTY.println("startBlock-ID: " + startBlock.getId()); // bailout of if this occurs in product mode. - throw new CiBailout("liveIn set of first block must be empty"); + throw new GraalInternalError("liveIn set of first block must be empty"); } } @@ -860,7 +860,7 @@ for (int operandNum = 0; operandNum < blockData.get(ir.cfg.getStartBlock()).liveIn.size(); operandNum++) { if (blockData.get(ir.cfg.getStartBlock()).liveIn.get(operandNum)) { CiValue operand = operandFor(operandNum); - TTY.println(" var %d; operand=%s", operandNum, operand.toString()); + TTY.println(" var %d; operand=%s; node=%s", operandNum, operand.toString(), gen.valueForOperand(operand)); for (int j = 0; j < numBlocks; j++) { Block block = blockAt(j); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Fri Apr 20 13:44:06 2012 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.virtual.*; public class DebugInfoBuilder { @@ -54,7 +55,13 @@ FrameState current = topState; do { for (Node n : current.virtualObjectMappings()) { - VirtualObjectFieldNode field = (VirtualObjectFieldNode) n; + Node p = n; + while (p instanceof PhiNode) { + PhiNode phi = (PhiNode) p; + assert phi.type() == PhiType.Virtual; + p = phi.valueAt(0); + } + VirtualObjectFieldNode field = (VirtualObjectFieldNode) p; // null states occur for objects with 0 fields if (field != null && !objectStates.containsKey(field.object())) { objectStates.put(field.object(), field); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Apr 20 13:44:06 2012 +0200 @@ -27,6 +27,7 @@ import static com.oracle.max.cri.ci.CiValue.*; import java.util.*; +import java.util.Map.Entry; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.util.*; @@ -173,6 +174,15 @@ return nodeOperands.get(node); } + public ValueNode valueForOperand(CiValue value) { + for (Entry entry : nodeOperands.entries()) { + if (entry.getValue() == value) { + return (ValueNode) entry.getKey(); + } + } + return null; + } + /** * Creates a new {@linkplain Variable variable}. * @param kind The kind of the new variable. @@ -480,13 +490,15 @@ CiValue[] params = new CiValue[incomingArguments.locations.length]; for (int i = 0; i < params.length; i++) { params[i] = toStackKind(incomingArguments.locations[i]); + if (CiValueUtil.isStackSlot(params[i])) { + CiStackSlot slot = CiValueUtil.asStackSlot(params[i]); + if (slot.inCallerFrame() && !lir.hasArgInCallerFrame()) { + lir.setHasArgInCallerFrame(); + } + } } - append(new ParametersOp(params)); - XirSnippet prologue = xir.genPrologue(null, method); - if (prologue != null) { - emitXir(prologue, null, null, false); - } + append(new ParametersOp(params)); for (LocalNode local : graph.getNodes(LocalNode.class)) { CiValue param = params[local.index()]; @@ -580,24 +592,13 @@ } @Override - public void visitExceptionObject(ExceptionObjectNode x) { - XirSnippet snippet = xir.genExceptionObject(site(x)); - LIRDebugInfo info = state(); - emitXir(snippet, x, info, true); - } - - @Override public void visitReturn(ReturnNode x) { CiValue operand = CiValue.IllegalValue; if (!x.kind().isVoid()) { operand = resultOperandFor(x.kind()); emitMove(operand(x.result()), operand); } - XirSnippet epilogue = xir.genEpilogue(site(x), method); - if (epilogue != null) { - emitXir(epilogue, x, null, false); - emitReturn(operand); - } + emitReturn(operand); } protected abstract void emitReturn(CiValue input); @@ -611,11 +612,11 @@ moveToPhi(end.merge(), end); } + /** + * Runtime specific classes can override this to insert a safepoint at the end of a loop. + */ @Override public void visitLoopEnd(LoopEndNode x) { - if (GraalOptions.GenLoopSafepoints && x.hasSafepointPolling()) { - emitSafepointPoll(x); - } } private ArrayList phiValues = new ArrayList<>(); @@ -661,14 +662,6 @@ } } - - public void emitSafepointPoll(FixedNode x) { - if (!lastState.method().noSafepointPolls()) { - XirSnippet snippet = xir.genSafepointPoll(site(x)); - emitXir(snippet, x, state(), false); - } - } - @Override public void emitIf(IfNode x) { assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination"; diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformDataResolver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformDataResolver.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,196 @@ +/* + * 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.Map.Entry; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.NodeClass.NodeClassIterator; +import com.oracle.graal.graph.NodeClass.Position; +import com.oracle.graal.nodes.*; + + + +public class LoopTransformDataResolver { + private List resolvables = new LinkedList<>(); + + private abstract static class ResolvableSuperBlock { + final SuperBlock block; + public ResolvableSuperBlock(SuperBlock block) { + this.block = block; + } + public abstract void resolve(); + } + + private static class PeeledResolvableSuperBlock extends ResolvableSuperBlock{ + final SuperBlock peel; + final boolean nextIteration; + public PeeledResolvableSuperBlock(SuperBlock peeled, SuperBlock peel, boolean nextIteration) { + super(peeled); + this.peel = peel; + this.nextIteration = nextIteration; + } + @Override + public void resolve() { + if (nextIteration) { + SuperBlock peeled = block; + LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry(); + Map dup = peel.getDuplicationMapping(); + List newPhis = new LinkedList<>(); + for (PhiNode phi : loopBegin.phis().snapshot()) { + ValueNode first = null; + if (loopBegin.loopEnds().count() == 1) { + ValueNode b = phi.valueAt(loopBegin.loopEnds().first()); // back edge value + first = prim(b); // corresponding value in the peel + } else { + Map reverseEnds = new HashMap<>(); // map peel's exit to the corresponding loop exits + MergeNode merge = null; // look for the merge if the peel's exits + for (LoopEndNode end : loopBegin.loopEnds()) { + EndNode newEnd = (EndNode) dup.get(end); + if (newEnd != null) { + reverseEnds.put(newEnd, end); + if (prim(phi.valueAt(end)) != null) { + merge = newEnd.merge(); + } + } + } + if (merge != null) { // found values of interest (backedge values that exist in the peel) + PhiNode firstPhi = loopBegin.graph().add(new PhiNode(phi.kind(), merge, phi.type())); + for (EndNode end : merge.forwardEnds()) { + LoopEndNode loopEnd = reverseEnds.get(end); + ValueNode prim = prim(phi.valueAt(loopEnd)); + assert prim != null; + firstPhi.addInput(prim); + } + first = firstPhi; + merge.stateAfter().replaceFirstInput(phi, firstPhi); // fix the merge's state after (see SuperBlock.mergeExits) + } + } + if (first != null) { // create a new phi (we don't patch the old one since some usages of the old one may still be valid) + PhiNode newPhi = loopBegin.graph().add(new PhiNode(phi.kind(), loopBegin, phi.type())); + newPhi.addInput(first); + for (LoopEndNode end : loopBegin.orderedLoopEnds()) { + newPhi.addInput(phi.valueAt(end)); + } + dup.put(phi, newPhi); + newPhis.add(newPhi); + for (Node usage : phi.usages().snapshot()) { + if (dup.get(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 = (PhiNode) dup.get(v); + if (newV != null) { + phi.setValueAt(i, newV); + } + } + } + } + } + } + + /** + * Gets the corresponding value in the peel. + * @param b original value + * @return corresponding value in the peel + */ + public ValueNode prim(ValueNode b) { + SuperBlock peeled = block; + LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry(); + Map dup = peel.getDuplicationMapping(); + if (loopBegin.isPhiAtMerge(b)) { + PhiNode phi = (PhiNode) b; + return phi.valueAt(loopBegin.forwardEnd()); + } else { + ValueNode v = (ValueNode) dup.get(b); + if (v == null && nextIteration) { + // may not be right in inversion case + return b; + } + return v; + } + } + } + + private static class PeelResolvableSuperBlock extends ResolvableSuperBlock{ + final SuperBlock peeled; + public PeelResolvableSuperBlock(SuperBlock peel, SuperBlock peeled) { + super(peel); + this.peeled = peeled; + } + @Override + public void resolve() { + SuperBlock peel = block; + LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry(); + for (Entry entry : peel.getDuplicationMapping().entrySet()) { + Node oriNode = entry.getKey(); + Node newNode = entry.getValue(); + for (NodeClassIterator iter = oriNode.inputs().iterator(); iter.hasNext();) { + Position pos = iter.nextPosition(); + if (pos.isValidFor(newNode, oriNode) && pos.get(newNode) == null) { + Node oriInput = pos.get(oriNode); + // oriInput is not checked against null because oriNode.inputs().iterator() only iterates over non-null pos/input + Node v; + if (loopBegin.isPhiAtMerge(oriInput)) { + PhiNode phi = (PhiNode) oriInput; + v = phi.valueAt(loopBegin.forwardEnd()); + } else { + v = oriInput; + } + pos.set(newNode, v); + } + } + } + } + } + + public class WholeLoop { + private final SuperBlock from; + public WholeLoop(SuperBlock from) { + this.from = from; + } + public void peeled(SuperBlock peel) { + resolvables.add(new PeelResolvableSuperBlock(peel, from)); + resolvables.add(new PeeledResolvableSuperBlock(from, peel, true)); + } + + } + + public void resolve() { + for (ResolvableSuperBlock resolvable : this.resolvables) { + resolvable.resolve(); + } + } + + public WholeLoop wholeLoop(SuperBlock block) { + return new WholeLoop(block); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,68 @@ +/* + * 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.lir.cfg.*; +import com.oracle.graal.nodes.*; + + +public class LoopTransformUtil { + + public static void peel(Loop loop) { + peel(loop, wholeLoop(loop)); + } + + public static void peel(Loop loop, SuperBlock wholeLoop) { + SuperBlock peel = wholeLoop.duplicate(); // duplicates the nodes, merges early exits + + peel.insertBefore(loop.loopBegin().forwardEnd()); // connects peeled part's CFG + + LoopTransformDataResolver resolver = new LoopTransformDataResolver(); + resolver.wholeLoop(wholeLoop).peeled(peel); // block (comming from the loop) was peeled into peel + resolver.resolve(); + + peel.finish(); + } + + public static SuperBlock wholeLoop(Loop loop) { + List blocks = new LinkedList<>(); + List earlyExits = new LinkedList<>(); + for (Block b : loop.blocks) { + blocks.add(b.getBeginNode()); + } + for (Block b : loop.exits) { + earlyExits.add(b.getBeginNode()); + } + return new SuperBlock(loop.loopBegin(), loop.loopBegin(), blocks, earlyExits, loop.loopBegin()); + } + + public static int estimateSize(Loop loop) { + int fixed = 0; + for (Block b : loop.blocks) { + fixed += b.getBeginNode().getBlockNodes().count(); + } + return fixed * 3; + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,356 @@ +/* + * 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.Map.Entry; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; + +public class SuperBlock { + protected BeginNode entry; + protected BeginNode exit; + protected List blocks; + protected List earlyExits; + protected LoopBeginNode loop; + protected Map duplicationMapping; + protected SuperBlock original; + protected NodeBitMap loopNodes; + + public SuperBlock(BeginNode entry, BeginNode exit, List blocks, List earlyExits, LoopBeginNode loop) { + this.entry = entry; + this.exit = exit; + this.blocks = blocks; + this.earlyExits = earlyExits; + this.loop = loop; + assert blocks.contains(entry); + assert !blocks.contains(exit) || exit == entry; + } + + public Map getDuplicationMapping() { + return duplicationMapping; + } + + public BeginNode getEntry() { + return entry; + } + + public NodeBitMap loopNodes() { + if (loopNodes == null) { + loopNodes = computeNodes(); + } + return loopNodes; + } + + public SuperBlock duplicate() { + NodeBitMap nodes = loopNodes(); + Map replacements = new HashMap<>(); + StructuredGraph graph = (StructuredGraph) entry.graph(); + BeginNode newEntry = graph.add(new BeginNode()); + BeginNode newExit = null; + List newEarlyExits = new ArrayList<>(earlyExits.size()); + if (!(exit instanceof MergeNode)) { + newExit = graph.add(new BeginNode()); + replacements.put(exit, newExit); + } + replacements.put(entry, newEntry); // no merge/loop begin + for (BeginNode earlyExit : earlyExits) { + BeginNode newEarlyExit = graph.add(new BeginNode()); + newEarlyExits.add(newEarlyExit); + replacements.put(earlyExit, newEarlyExit); + } + if (loop != null) { + for (LoopEndNode end : loop.loopEnds()) { + if (nodes.isMarked(end)) { + replacements.put(end, graph.add(new EndNode())); + } + } + } + Map duplicates = graph.addDuplicates(nodes, replacements); + if (exit instanceof MergeNode) { + newExit = mergeExits(replacements, graph, duplicates, (MergeNode) exit); + } + + List newBlocks = new ArrayList<>(blocks.size()); + for (BeginNode block : blocks) { + BeginNode newBlock = (BeginNode) duplicates.get(block); + if (newBlock == null) { + newBlock = (BeginNode) replacements.get(block); + } + assert newBlock != null : block; + newBlocks.add(newBlock); + } + for (Entry e : replacements.entrySet()) { + duplicates.put(e.getKey(), e.getValue()); + } + SuperBlock superBlock = new SuperBlock(newEntry, newExit, newBlocks, newEarlyExits, loop); + superBlock.duplicationMapping = duplicates; + superBlock.original = this; + return superBlock; + } + + private BeginNode mergeExits(Map replacements, StructuredGraph graph, Map duplicates, MergeNode mergeExit) { + BeginNode newExit; + List endsToMerge = new LinkedList<>(); + if (mergeExit == loop) { + LoopBeginNode loopBegin = (LoopBeginNode) mergeExit; + for (LoopEndNode le : loopBegin.loopEnds()) { + Node duplicate = replacements.get(le); + if (duplicate != null) { + endsToMerge.add((EndNode) duplicate); + } + } + } else { + for (EndNode end : mergeExit.forwardEnds()) { + Node duplicate = duplicates.get(end); + if (duplicate != null) { + endsToMerge.add((EndNode) duplicate); + } + } + } + + if (endsToMerge.size() == 1) { + EndNode end = endsToMerge.get(0); + assert end.usages().count() == 0; + newExit = graph.add(new BeginNode()); + end.replaceAtPredecessors(newExit); + end.safeDelete(); + } else { + assert endsToMerge.size() > 1; + MergeNode newExitMerge = graph.add(new MergeNode()); + newExit = newExitMerge; + FrameState state = mergeExit.stateAfter().duplicate(); + newExitMerge.setStateAfter(state); // this state is wrong (incudes phis from the loop begin) needs to be fixed while resolving data + for (EndNode end : endsToMerge) { + newExitMerge.addForwardEnd(end); + } + } + return newExit; + } + + public void finish() { + if (original != null) { + mergeEarlyExits((StructuredGraph) entry.graph(), original.earlyExits, duplicationMapping); + } + } + + private static void mergeEarlyExits(StructuredGraph graph, List earlyExits, Map duplicates) { + for (BeginNode earlyExit : earlyExits) { + BeginNode newEarlyExit = (BeginNode) duplicates.get(earlyExit); + assert newEarlyExit != null; + MergeNode merge = graph.add(new MergeNode()); + EndNode originalEnd = graph.add(new EndNode()); + EndNode newEnd = graph.add(new EndNode()); + merge.addForwardEnd(originalEnd); + merge.addForwardEnd(newEnd); + FixedNode next = earlyExit.next(); + earlyExit.setNext(originalEnd); + newEarlyExit.setNext(newEnd); + merge.setNext(next); + FrameState exitState = earlyExit.stateAfter(); + FrameState state = exitState.duplicate(); + merge.setStateAfter(state); + for (ValueProxyNode vpn : earlyExit.proxies().snapshot()) { + ValueNode replaceWith; + ValueProxyNode newVpn = (ValueProxyNode) duplicates.get(vpn); + if (newVpn != null) { + PhiNode phi = graph.add(new PhiNode(vpn.kind(), merge, vpn.type())); + phi.addInput(vpn); + phi.addInput(newVpn); + if (vpn.type() == PhiType.Value) { + replaceWith = phi; + } else { + assert vpn.type() == PhiType.Virtual; + VirtualObjectFieldNode vof = (VirtualObjectFieldNode) GraphUtil.unProxify(vpn); + VirtualObjectFieldNode newVof = (VirtualObjectFieldNode) GraphUtil.unProxify(newVpn); + replaceWith = mergeVirtualChain(graph, vof, newVof, phi, earlyExit, newEarlyExit, merge); + } + } else { + replaceWith = vpn.value(); + } + state.replaceFirstInput(vpn, replaceWith); + for (Node usage : vpn.usages().snapshot()) { + if (usage != exitState && !merge.isPhiAtMerge(usage)) { + usage.replaceFirstInput(vpn, replaceWith); + } + } + } + } + } + + private static ValueProxyNode findProxy(ValueNode value, BeginNode proxyPoint) { + for (ValueProxyNode vpn : proxyPoint.proxies()) { + ValueNode v = vpn; + while (v instanceof ValueProxyNode) { + v = ((ValueProxyNode) v).value(); + if (v == value) { + return vpn; + } + } + } + return null; + } + + private static ValueNode mergeVirtualChain( + StructuredGraph graph, + VirtualObjectFieldNode vof, + VirtualObjectFieldNode newVof, + PhiNode vPhi, + BeginNode earlyExit, + BeginNode newEarlyExit, + MergeNode merge) { + VirtualObjectNode vObject = vof.object(); + assert newVof.object() == vObject; + ValueNode[] virtualState = virtualState(vof); + ValueNode[] newVirtualState = virtualState(newVof); + ValueNode chain = vPhi; + for (int i = 0; i < virtualState.length; i++) { + ValueNode value = virtualState[i]; + ValueNode newValue = newVirtualState[i]; + assert value.kind() == newValue.kind(); + if (value != newValue) { + PhiNode valuePhi = graph.add(new PhiNode(value.kind(), merge, PhiType.Value)); + ValueProxyNode inputProxy = findProxy(value, earlyExit); + if (inputProxy != null) { + ValueProxyNode newInputProxy = findProxy(newValue, newEarlyExit); + assert newInputProxy != null : "no proxy for " + newValue + " at " + newEarlyExit; + valuePhi.addInput(inputProxy); + valuePhi.addInput(newInputProxy); + } else { + valuePhi.addInput(graph.unique(new ValueProxyNode(value, earlyExit, PhiType.Value))); + valuePhi.addInput(newValue); + } + chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i)); + } + } + return chain; + } + + private static ValueNode[] virtualState(VirtualObjectFieldNode vof) { + VirtualObjectNode vObj = vof.object(); + int fieldsCount = vObj.fieldsCount(); + int dicovered = 0; + ValueNode[] state = new ValueNode[fieldsCount]; + ValueNode currentField = vof; + do { + if (currentField instanceof VirtualObjectFieldNode) { + int index = ((VirtualObjectFieldNode) currentField).index(); + if (state[index] == null) { + dicovered++; + state[index] = ((VirtualObjectFieldNode) currentField).input(); + if (dicovered >= fieldsCount) { + break; + } + } + currentField = ((VirtualObjectFieldNode) currentField).lastState(); + } else { + assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField; + currentField = ((PhiNode) currentField).valueAt(0); + } + } while (currentField != null); + return state; + } + + private NodeBitMap computeNodes() { + NodeBitMap nodes = entry.graph().createNodeBitMap(); + 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(); + assert stateAfter != null; + nodes.mark(stateAfter); + 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, ""); + } + } + } + + if (entry instanceof LoopBeginNode) { + for (PhiNode phi : ((LoopBeginNode) entry).phis()) { + nodes.clear(phi); + } + } + + return nodes; + } + + private static boolean markFloating(Node n, NodeBitMap loopNodes, String ind) { + //System.out.println(ind + "markFloating(" + n + ")"); + if (loopNodes.isMarked(n)) { + return true; + } + if (n instanceof FixedNode) { + return false; + } + boolean mark = false; + if (n instanceof PhiNode) { + mark = loopNodes.isMarked(((PhiNode) n).merge()); + if (mark) { + loopNodes.mark(n); + } else { + return false; + } + } + for (Node usage : n.usages()) { + if (markFloating(usage, loopNodes, " " + ind)) { + mark = true; + } + } + if (mark) { + loopNodes.mark(n); + return true; + } + return false; + } + + public void insertBefore(FixedNode fixed) { + assert entry.predecessor() == null; + assert exit.next() == null; + fixed.replaceAtPredecessors(entry); + exit.setNext(fixed); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -130,8 +130,12 @@ @Override public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - while (!(virtualObjectField instanceof PhiNode)) { - virtualObjectField = ((VirtualObjectFieldNode) virtualObjectField).lastState(); + while (!loopBegin.isPhiAtMerge(virtualObjectField)) { + if (virtualObjectField instanceof PhiNode) { + virtualObjectField = ((PhiNode) virtualObjectField).valueAt(0); + } else { + virtualObjectField = ((VirtualObjectFieldNode) virtualObjectField).lastState(); + } } for (BlockExitState loopEndState : loopEndStates) { ((PhiNode) virtualObjectField).addInput(loopEndState.virtualObjectField); @@ -184,6 +188,11 @@ FixedNode next = node.next(); graph.removeFixed(node); + for (ValueProxyNode vpn : virtual.usages().filter(ValueProxyNode.class).snapshot()) { + assert vpn.value() == virtual; + graph.replaceFloating(vpn, virtual); + } + if (virtual.fieldsCount() > 0) { final BlockExitState startState = new BlockExitState(escapeFields, virtual); final PostOrderNodeIterator iterator = new PostOrderNodeIterator(next, startState) { @@ -193,9 +202,25 @@ if (changedField != -1) { state.updateField(changedField); } + if (curNode instanceof LoopExitNode) { + state.virtualObjectField = graph.unique(new ValueProxyNode(state.virtualObjectField, (LoopExitNode) curNode, PhiType.Virtual)); + for (int i = 0; i < state.fieldState.length; i++) { + state.fieldState[i] = graph.unique(new ValueProxyNode(state.fieldState[i], (LoopExitNode) curNode, PhiType.Value)); + } + } if (!curNode.isDeleted() && curNode instanceof StateSplit && ((StateSplit) curNode).stateAfter() != null) { if (state.virtualObjectField != null) { - ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(state.virtualObjectField); + ValueNode v = state.virtualObjectField; + if (curNode instanceof LoopBeginNode) { + while (!((LoopBeginNode) curNode).isPhiAtMerge(v)) { + if (v instanceof PhiNode) { + v = ((PhiNode) v).valueAt(0); + } else { + v = ((VirtualObjectFieldNode) v).lastState(); + } + } + } + ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v); } } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopTransformPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopTransformPhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,60 @@ +/* + * 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; + +import java.util.*; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.loop.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + +public class LoopTransformPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); + Loop[] loops = cfg.getLoops(); + // outermost first + Arrays.sort(loops, new Comparator() { + @Override + public int compare(Loop o1, Loop o2) { + return o1.depth - o2.depth; + } + }); + for (Loop loop : loops) { + double entryProbability = loop.loopBegin().forwardEnd().probability(); + if (entryProbability > GraalOptions.MinimumPeelProbability + && LoopTransformUtil.estimateSize(loop) + graph.getNodeCount() < GraalOptions.MaximumDesiredSize) { + Debug.log("Peeling %s", loop); + LoopTransformUtil.peel(loop); + Debug.dump(graph, "After peeling %s", loop); + } + } + } + } + + +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -30,6 +30,9 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.max.cri.ri.*; +/** + * Processes all {@link Lowerable} nodes to do their lowering. + */ public class LoweringPhase extends Phase { private final GraalRuntime runtime; diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,44 @@ +/* + * 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(); + } + } + } + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -227,6 +227,9 @@ if (newInstance instanceof ValueNode && ((ValueNode) newInstance).kind() != CiKind.Object) { StructuredGraph graph = (StructuredGraph) newInstance.graph(); for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { + for (ValueProxyNode vpn : checkCastNode.usages().filter(ValueProxyNode.class).snapshot()) { + graph.replaceFloating(vpn, checkCastNode); + } for (Node checkCastUsage : checkCastNode.usages().snapshot()) { if (checkCastUsage instanceof ValueAnchorNode) { ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -38,7 +38,10 @@ private ControlFlowGraph cfg; private NodeMap earliestCache; - private BlockMap> nodesFor; + /** + * Map from blocks to the nodes in each block. + */ + private BlockMap> blockToNodesMap; public SchedulePhase() { super("Schedule"); @@ -48,7 +51,7 @@ protected void run(StructuredGraph graph) { cfg = ControlFlowGraph.compute(graph, true, true, true, false); earliestCache = graph.createNodeMap(); - nodesFor = new BlockMap<>(cfg); + blockToNodesMap = new BlockMap<>(cfg); assignBlockToNodes(graph); sortNodesWithinBlocks(graph); @@ -56,7 +59,7 @@ public void scheduleGraph() { for (Block block : cfg.getBlocks()) { - List nodeList = nodesFor.get(block); + List nodeList = blockToNodesMap.get(block); ScheduledNode last = null; for (Node node : nodeList) { if (!(node instanceof FrameState)) { @@ -73,19 +76,25 @@ return cfg; } - public BlockMap> getNodesFor() { - return nodesFor; + /** + * Gets the map from each block to the nodes in the block. + */ + public BlockMap> getBlockToNodesMap() { + return blockToNodesMap; } + /** + * Gets the nodes in a given block. + */ public List nodesFor(Block block) { - return nodesFor.get(block); + return blockToNodesMap.get(block); } private void assignBlockToNodes(StructuredGraph graph) { for (Block block : cfg.getBlocks()) { List nodes = new ArrayList<>(); - assert nodesFor.get(block) == null; - nodesFor.put(block, nodes); + assert blockToNodesMap.get(block) == null; + blockToNodesMap.put(block, nodes); for (Node node : block.getNodes()) { nodes.add(node); } @@ -108,6 +117,7 @@ return; } assert !(n instanceof PhiNode) : n; + assert !(n instanceof MergeNode); // if in CFG, schedule at the latest position possible in the outermost loop possible Block latestBlock = latestBlock(n); Block block; @@ -120,9 +130,8 @@ } else { block = latestBlock; } - assert !(n instanceof MergeNode); cfg.getNodeToBlock().set(n, block); - nodesFor.get(block).add(n); + blockToNodesMap.get(block).add(n); } private Block latestBlock(Node n) { @@ -264,7 +273,7 @@ } private void sortNodesWithinBlocks(Block b, NodeBitMap map) { - List instructions = nodesFor.get(b); + List instructions = blockToNodesMap.get(b); List sortedInstructions = new ArrayList<>(instructions.size() + 2); assert !map.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; @@ -298,7 +307,7 @@ sortedInstructions.add(b.getEndNode()); } } - nodesFor.put(b, sortedInstructions); + blockToNodesMap.put(b, sortedInstructions); } private void addToSorting(Block b, Node i, List sortedInstructions, NodeBitMap map) { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Fri Apr 20 13:44:06 2012 +0200 @@ -24,18 +24,26 @@ import java.lang.reflect.*; -import com.oracle.max.asm.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.cri.xir.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.*; /** * The {@code Backend} class represents a compiler backend for Graal. */ public abstract class Backend { + + /** + * The name of the system property whose value (if non-null) specifies the fully qualified + * name of the class to be instantiated by {@link #create(RiRuntime, CiTarget)}. + */ + public static final String BACKEND_CLASS_PROPERTY = "graal.compiler.backend.class"; + public final RiRuntime runtime; public final CiTarget target; @@ -44,8 +52,13 @@ this.target = target; } - public static Backend create(CiArchitecture arch, RiRuntime runtime, CiTarget target) { - String className = arch.getClass().getName().replace("com.oracle.max.asm", "com.oracle.graal.compiler") + "Backend"; + /** + * Creates the architecture and runtime specific back-end object. + * The class of the object instantiated must be in the {@link #BACKEND_CLASS_PROPERTY} system property. + */ + public static Backend create(RiRuntime runtime, CiTarget target) { + String className = System.getProperty(BACKEND_CLASS_PROPERTY); + assert className != null : "System property must be defined: " + BACKEND_CLASS_PROPERTY; try { Class c = Class.forName(className); Constructor cons = c.getDeclaredConstructor(RiRuntime.class, CiTarget.class); @@ -55,9 +68,46 @@ } } - public abstract FrameMap newFrameMap(RiRegisterConfig registerConfig); + public FrameMap newFrameMap(RiRegisterConfig registerConfig) { + return new FrameMap(runtime, target, registerConfig); + } + public abstract LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir); - public abstract AbstractAssembler newAssembler(RiRegisterConfig registerConfig); + + public abstract TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir); + public abstract CiXirAssembler newXirAssembler(); + /** + * Emits code to do stack overflow checking. + * + * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate the current frame + */ + protected static void emitStackOverflowCheck(TargetMethodAssembler tasm, boolean afterFrameInit) { + if (GraalOptions.StackShadowPages > 0) { + int frameSize = tasm.frameMap.frameSize(); + if (frameSize > 0) { + int lastFramePage = frameSize / tasm.target.pageSize; + // emit multiple stack bangs for methods with frames larger than a page + for (int i = 0; i <= lastFramePage; i++) { + int disp = (i + GraalOptions.StackShadowPages) * tasm.target.pageSize; + if (afterFrameInit) { + disp -= frameSize; + } + tasm.asm.bangStack(disp); + } + } + } + } + + /** + * Emits the code for a given method. This includes any architecture/runtime specific + * prefix/suffix. A prefix typically contains the code for setting up the frame, + * spilling callee-save registers, stack overflow checking, handling multiple entry + * points etc. A suffix may contain out-of-line stubs and method end guard instructions. + * + * @param the method associated with {@code lir} + * @param lir the LIR of {@code method} + */ + public abstract void emitCode(TargetMethodAssembler tasm, RiResolvedMethod method, LIR lir); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64Backend.java Fri Apr 13 15:52:25 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +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.target.amd64; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.cri.xir.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.*; - -/** - * The {@code X86Backend} class represents the backend for the AMD64 architecture. - */ -public class AMD64Backend extends Backend { - - public AMD64Backend(RiRuntime runtime, CiTarget target) { - super(runtime, target); - } - /** - * Creates a new LIRGenerator for x86. - * @param compilation the compilation for which to create the LIR generator - * @return an appropriate LIR generator instance - */ - @Override - public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) { - return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir); - } - - @Override - public FrameMap newFrameMap(RiRegisterConfig registerConfig) { - return new FrameMap(runtime, target, registerConfig); - } - - @Override - public AbstractAssembler newAssembler(RiRegisterConfig registerConfig) { - return new AMD64MacroAssembler(target, registerConfig); - } - - @Override - public CiXirAssembler newXirAssembler() { - return new AMD64XirAssembler(target); - } -} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java Fri Apr 20 13:44:06 2012 +0200 @@ -33,7 +33,7 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; -public class AMD64DeoptimizationStub extends AMD64SlowPath { +public class AMD64DeoptimizationStub extends AMD64Code { public final Label label = new Label(); public final LIRDebugInfo info; public final RiDeoptAction action; diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Fri Apr 20 13:44:06 2012 +0200 @@ -74,7 +74,7 @@ /** * This class implements the X86-specific portion of the LIR generator. */ -public class AMD64LIRGenerator extends LIRGenerator { +public abstract class AMD64LIRGenerator extends LIRGenerator { private static final CiRegisterValue RAX_I = AMD64.rax.asValue(CiKind.Int); private static final CiRegisterValue RAX_L = AMD64.rax.asValue(CiKind.Long); @@ -97,7 +97,6 @@ public AMD64LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) { super(graph, runtime, target, frameMap, method, lir, xir); - lir.methodEndMarker = new AMD64MethodEndStub(); lir.spillMoveFactory = new AMD64SpillMoveFactory(); } @@ -575,11 +574,13 @@ Variable newValue = load(operand(node.newValue())); CiAddress address; + int displacement = node.displacement(); CiValue index = operand(node.offset()); if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong())) { - address = new CiAddress(kind, load(operand(node.object())), (int) asConstant(index).asLong()); + displacement += (int) asConstant(index).asLong(); + address = new CiAddress(kind, load(operand(node.object())), displacement); } else { - address = new CiAddress(kind, load(operand(node.object())), load(index), CiAddress.Scale.Times1, 0); + address = new CiAddress(kind, load(operand(node.object())), load(index), CiAddress.Scale.Times1, displacement); } CiRegisterValue rax = AMD64.rax.asValue(kind); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64MethodEndStub.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64MethodEndStub.java Fri Apr 13 15:52:25 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +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.target.amd64; - -import com.oracle.max.asm.target.amd64.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64MethodEndStub extends AMD64SlowPath { - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - for (int i = 0; i < GraalOptions.MethodEndBreakpointGuards; ++i) { - masm.int3(); - } - } -} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirAssembler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirAssembler.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirAssembler.java Fri Apr 20 13:44:06 2012 +0200 @@ -188,15 +188,10 @@ boundLabels.add(label); break; case Safepoint: - case Align: - case StackOverflowCheck: - case PushFrame: - case PopFrame: case Push: case Pop: case Mark: case Nop: - case RawBytes: case ShouldNotReachHere: break; default: diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirOp.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirOp.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirOp.java Fri Apr 20 13:44:06 2012 +0200 @@ -28,6 +28,10 @@ import java.util.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; import com.oracle.max.asm.*; import com.oracle.max.asm.target.amd64.*; import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; @@ -38,11 +42,6 @@ import com.oracle.max.cri.xir.CiXirAssembler.XirInstruction; import com.oracle.max.cri.xir.CiXirAssembler.XirLabel; import com.oracle.max.cri.xir.CiXirAssembler.XirMark; -import com.oracle.graal.compiler.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.asm.*; public class AMD64XirOp extends LIRXirInstruction { public AMD64XirOp(XirSnippet snippet, CiValue[] operands, CiValue outputOperand, CiValue[] inputs, CiValue[] temps, int[] inputOperandIndices, int[] tempOperandIndices, int outputOperandIndex, @@ -86,7 +85,7 @@ } } - private class SlowPath extends AMD64SlowPath { + private class SlowPath extends AMD64Code { public final Label[] labels; public SlowPath(Label[] labels) { @@ -391,52 +390,6 @@ masm.nullCheck(asRegister(pointer)); break; } - case Align: { - masm.align((Integer) inst.extra); - break; - } - case StackOverflowCheck: { - int frameSize = tasm.frameMap.frameSize(); - int lastFramePage = frameSize / tasm.target.pageSize; - // emit multiple stack bangs for methods with frames larger than a page - for (int i = 0; i <= lastFramePage; i++) { - int offset = (i + GraalOptions.StackShadowPages) * tasm.target.pageSize; - // Deduct 'frameSize' to handle frames larger than the shadow - bangStackWithOffset(tasm, masm, offset - frameSize); - } - break; - } - case PushFrame: { - int frameSize = tasm.frameMap.frameSize(); - masm.decrementq(AMD64.rsp, frameSize); // does not emit code for frameSize == 0 - if (GraalOptions.ZapStackOnMethodEntry) { - final int intSize = 4; - for (int i = 0; i < frameSize / intSize; ++i) { - masm.movl(new CiAddress(CiKind.Int, AMD64.rsp.asValue(), i * intSize), 0xC1C1C1C1); - } - } - CiCalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout(); - if (csl != null && csl.size != 0) { - int frameToCSA = tasm.frameMap.offsetToCalleeSaveArea(); - assert frameToCSA >= 0; - masm.save(csl, frameToCSA); - } - break; - } - case PopFrame: { - int frameSize = tasm.frameMap.frameSize(); - - CiCalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout(); - if (csl != null && csl.size != 0) { - tasm.targetMethod.setRegisterRestoreEpilogueOffset(masm.codeBuffer.position()); - // saved all registers, restore all registers - int frameToCSA = tasm.frameMap.offsetToCalleeSaveArea(); - masm.restore(csl, frameToCSA); - } - - masm.incrementq(AMD64.rsp, frameSize); - break; - } case Push: { CiRegisterValue value = assureInRegister(tasm, masm, operands[inst.x().index]); masm.push(asRegister(value)); @@ -470,12 +423,6 @@ } break; } - case RawBytes: { - for (byte b : (byte[]) inst.extra) { - masm.codeBuffer.emitByte(b & 0xff); - } - break; - } case ShouldNotReachHere: { AMD64Call.shouldNotReachHere(tasm, masm); break; @@ -521,16 +468,6 @@ masm.jcc(cflag, label); } - /** - * @param offset the offset RSP at which to bang. Note that this offset is relative to RSP after RSP has been - * adjusted to allocated the frame for the method. It denotes an offset "down" the stack. - * For very large frames, this means that the offset may actually be negative (i.e. denoting - * a slot "up" the stack above RSP). - */ - private static void bangStackWithOffset(TargetMethodAssembler tasm, AMD64MacroAssembler masm, int offset) { - masm.movq(new CiAddress(tasm.target.wordKind, AMD64.RSP, -offset), AMD64.rax); - } - private static CiValue assureNot64BitConstant(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue value) { if (isConstant(value) && (value.kind == CiKind.Long || value.kind == CiKind.Object)) { CiRegisterValue register = tasm.frameMap.registerConfig.getScratchRegister().asValue(value.kind); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -141,7 +141,7 @@ out.print(succ + " "); } System.out.println(); - for (Node node : printSchedule.getNodesFor().get(block)) { + for (Node node : printSchedule.getBlockToNodesMap().get(block)) { out.println(" " + node + " (" + node.usages().size() + ")"); } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Fri Apr 20 13:44:06 2012 +0200 @@ -882,15 +882,7 @@ returnDuplicate.clearInputs(); Node n = invoke.next(); invoke.setNext(null); - if (n instanceof BeginNode) { - BeginNode begin = (BeginNode) n; - FixedNode next = begin.next(); - begin.setNext(null); - returnDuplicate.replaceAndDelete(next); - begin.safeDelete(); - } else { - returnDuplicate.replaceAndDelete(n); - } + returnDuplicate.replaceAndDelete(n); } invoke.node().clearInputs(); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Fri Apr 20 13:44:06 2012 +0200 @@ -158,6 +158,10 @@ } } + /** + * Searches the current debug scope, bottom up, for a context object that is an instance of a given type. + * The first such object found is returned. + */ @SuppressWarnings("unchecked") public static T contextLookup(Class clazz) { if (ENABLED) { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.examples/src/examples/HelloWorld.java --- a/graal/com.oracle.graal.examples/src/examples/HelloWorld.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.examples/src/examples/HelloWorld.java Fri Apr 20 13:44:06 2012 +0200 @@ -25,6 +25,20 @@ public class HelloWorld { public static void main(String[] args) { - System.out.println("hello world!"); + new HelloWorld(args).greet(); + } + + public HelloWorld(String[] args) { + name = args.length == 0 ? "world" : args[0]; + } + + public String name; + + public String getName() { + return name; + } + + public void greet() { + System.out.println("hello " + getName() + "!"); } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.graph/src/com/oracle/graal/graph/BitMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/BitMap.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/BitMap.java Fri Apr 20 13:44:06 2012 +0200 @@ -22,9 +22,8 @@ */ package com.oracle.graal.graph; -import java.io.Serializable; -import java.util.Arrays; -import java.util.BitSet; +import java.io.*; +import java.util.*; /** * Implements a bitmap that stores a single bit for a range of integers (0-n). @@ -114,7 +113,8 @@ assert length >= 0; this.size = length; if (length > BITS_PER_WORD) { - extra = new long[length >> ADDRESS_BITS_PER_WORD]; + int n = wordIndex(length - 1) + 1; + extra = new long[n]; } } @@ -357,10 +357,27 @@ } public void negate() { - low = ~low; - if (extra != null) { - for (int i = 0; i < extra.length; i++) { - extra[i] = ~extra[i]; + if (size == 0) { + return; + } + if (size < BITS_PER_WORD) { + long mask = (1L << size) - 1; + low = ~low & mask; + } else if (size == BITS_PER_WORD) { + low = ~low; + } else { + low = ~low; + if (extra != null) { + for (int i = 0; i < extra.length; i++) { + extra[i] = ~extra[i]; + if (i == extra.length - 1 && wordIndex(size) == i) { + if (bitInWord(size) != 0) { + long mask = (1L << bitInWord(size)) - 1; + extra[i] &= mask; + } + } + } + } } } @@ -597,17 +614,10 @@ * Returns a string representation of this bit map with every set bit represented as {@code '1'} * and every unset bit represented as {@code '0'}. The first character in the returned string represents * bit 0 in this bit map. - * - * @param length the number of bits represented in the returned string. If {@code length < 0 || length > size()}, - * then the value of {@link #length()} is used. */ public String toBinaryString() { - int length = length(); - if (length == 0) { - return ""; - } - StringBuilder sb = new StringBuilder(length); - for (int i = 0; i < length; ++i) { + StringBuilder sb = new StringBuilder(size); + for (int i = 0; i < size; ++i) { sb.append(get(i) ? '1' : '0'); } return sb.toString(); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Fri Apr 20 13:44:06 2012 +0200 @@ -352,6 +352,10 @@ node.getNodeClass().set(node, this, value); } + public boolean isValidFor(Node node, Node from) { + return node.getNodeClass().isValid(this, from.getNodeClass()); + } + @Override public int hashCode() { final int prime = 31; @@ -605,6 +609,18 @@ return true; } + public boolean isValid(Position pos, NodeClass from) { + long[] offsets = pos.input ? inputOffsets : successorOffsets; + if (pos.index >= offsets.length) { + return false; + } + long[] fromOffsets = pos.input ? from.inputOffsets : from.successorOffsets; + if (pos.index >= fromOffsets.length) { + return false; + } + return offsets[pos.index] == fromOffsets[pos.index]; + } + public Node get(Node node, Position pos) { long offset = pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index]; if (pos.subIndex == NOT_ITERABLE) { @@ -678,7 +694,7 @@ while (index < directInputCount) { Node input = getNode(node, inputOffsets[index]); if (input == old) { - assert other == null || inputTypes[index].isAssignableFrom(other.getClass()); + assert other == null || inputTypes[index].isAssignableFrom(other.getClass()); // : "Can not assign " + other.getClass() + " to " + inputTypes[index] + " in " + node; putNode(node, inputOffsets[index], other); return true; } @@ -700,7 +716,7 @@ while (index < directSuccessorCount) { Node successor = getNode(node, successorOffsets[index]); if (successor == old) { - assert other == null || successorTypes[index].isAssignableFrom(other.getClass()) : successorTypes[index] + " is not compatible with " + other.getClass(); + assert other == null || successorTypes[index].isAssignableFrom(other.getClass()); // : successorTypes[index] + " is not compatible with " + other.getClass(); putNode(node, successorOffsets[index], other); return true; } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.graph/test/com/oracle/graal/graph/test/TypedNodeIteratorTest.java --- a/graal/com.oracle.graal.graph/test/com/oracle/graal/graph/test/TypedNodeIteratorTest.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.graph/test/com/oracle/graal/graph/test/TypedNodeIteratorTest.java Fri Apr 20 13:44:06 2012 +0200 @@ -46,7 +46,7 @@ TestNode testNode = new TestNode("a"); Graph graph = new Graph(); graph.add(testNode); - testNode.delete(); + testNode.safeDelete(); assertEquals("", toString(graph.getNodes(TestNode.class))); } @@ -56,7 +56,7 @@ Graph graph = new Graph(); graph.add(new TestNode("a")); graph.add(testNode); - testNode.delete(); + testNode.safeDelete(); assertEquals("a", toString(graph.getNodes(TestNode.class))); graph.add(new TestNode("c")); assertEquals("ac", toString(graph.getNodes(TestNode.class))); @@ -77,7 +77,7 @@ TestNode c = new TestNode("c"); graph.add(c); assertTrue(iterator.hasNext()); - c.delete(); + c.safeDelete(); assertFalse(iterator.hasNext()); } @@ -90,11 +90,11 @@ for (int i = 0; i < name.length(); ++i) { char c = name.charAt(i); if (c == 'a') { - tn.delete(); + tn.safeDelete(); graph.add(new TestNode("b")); graph.add(new TestNode("c")); } else if (c == 'b') { - tn.delete(); + tn.safeDelete(); } else if (c == 'c') { graph.add(new TestNode("d")); graph.add(new TestNode("e")); @@ -107,9 +107,9 @@ } else if (c == 'd') { for (TestNode tn2 : graph.getNodes(TestNode.class)) { if (tn2.getName().equals("e")) { - tn2.delete(); + tn2.safeDelete(); } else if (tn2.getName().equals("c")) { - tn2.delete(); + tn2.safeDelete(); } } } else if (c == 'e') { @@ -146,7 +146,7 @@ assertEquals(3, z); } - private String toString(Iterable nodes) { + private static String toString(Iterable nodes) { StringBuilder sb = new StringBuilder(); for (TestNode tn : nodes) { sb.append(tn.getName()); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Fri Apr 20 13:44:06 2012 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.hotspot; -import java.io.*; import java.util.concurrent.*; import com.oracle.graal.compiler.*; @@ -133,8 +132,12 @@ } catch (CiBailout bailout) { Debug.metric("Bailouts").increment(); if (GraalOptions.ExitVMOnBailout) { + TTY.cachedOut.println(CiUtil.format("Bailout in %H.%n(%p)", method)); bailout.printStackTrace(TTY.cachedOut); System.exit(-1); + } else if (GraalOptions.PrintBailout) { + TTY.cachedOut.println(CiUtil.format("Bailout in %H.%n(%p)", method)); + bailout.printStackTrace(TTY.cachedOut); } } catch (Throwable t) { if (GraalOptions.ExitVMOnException) { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java Fri Apr 20 13:44:06 2012 +0200 @@ -23,12 +23,9 @@ package com.oracle.graal.hotspot; import java.io.*; +import java.lang.reflect.*; import java.net.*; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.cri.xir.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.graph.*; import com.oracle.graal.compiler.target.*; @@ -37,6 +34,10 @@ import com.oracle.graal.hotspot.logging.*; import com.oracle.graal.hotspot.ri.*; import com.oracle.graal.hotspot.server.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.xir.*; /** * Singleton class holding the instance of the GraalCompiler. @@ -128,6 +129,21 @@ // initialize compiler config = vmEntries.getConfiguration(); config.check(); + + if (Boolean.valueOf(System.getProperty("graal.printconfig"))) { + printConfig(config); + } + } + + private static void printConfig(HotSpotVMConfig config) { + Field[] fields = config.getClass().getDeclaredFields(); + for (Field f : fields) { + f.setAccessible(true); + try { + Logger.info(String.format("%9s %-40s = %s", f.getType().getSimpleName(), f.getName(), Logger.pretty(f.get(config)))); + } catch (Exception e) { + } + } } @Override @@ -159,7 +175,7 @@ generator = LoggingProxy.getProxy(RiXirGenerator.class, generator); } - Backend backend = Backend.create(target.arch, runtime, target); + Backend backend = Backend.create(runtime, target); generator.initialize(backend.newXirAssembler()); compiler = new GraalCompiler(getRuntime(), getTarget(), backend, generator); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Fri Apr 20 13:44:06 2012 +0200 @@ -109,8 +109,12 @@ String disassembleJava(HotSpotMethodResolved method); + StackTraceElement RiMethod_toStackTraceElement(HotSpotMethodResolved method, int bci); + Object executeCompiledMethod(HotSpotCompiledMethod method, Object arg1, Object arg2, Object arg3); + Object executeCompiledMethodVarargs(HotSpotCompiledMethod method, Object... args); + int RiMethod_vtableEntryOffset(HotSpotMethodResolved method); long[] getDeoptedLeafGraphIds(); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Fri Apr 20 13:44:06 2012 +0200 @@ -157,9 +157,15 @@ public native String disassembleJava(HotSpotMethodResolved method); @Override + public native StackTraceElement RiMethod_toStackTraceElement(HotSpotMethodResolved method, int bci); + + @Override public native Object executeCompiledMethod(HotSpotCompiledMethod method, Object arg1, Object arg2, Object arg3); @Override + public native Object executeCompiledMethodVarargs(HotSpotCompiledMethod method, Object... args); + + @Override public native int RiMethod_vtableEntryOffset(HotSpotMethodResolved method); @Override diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Fri Apr 20 13:44:06 2012 +0200 @@ -147,7 +147,7 @@ /** * This method is the first method compiled during bootstrapping. Put any code in there that warms up compiler paths - * that are otherwise no exercised during bootstrapping and lead to later deoptimization when application code is + * that are otherwise not exercised during bootstrapping and lead to later deoptimization when application code is * compiled. */ @SuppressWarnings("unused") diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java Fri Apr 20 13:44:06 2012 +0200 @@ -33,13 +33,27 @@ public static final boolean ENABLED = Boolean.valueOf(System.getProperty("graal.debug")); private static final int SPACING = 4; - private static Deque openStack = new LinkedList<>(); - private static boolean open = false; - private static int level = 0; + private static final ThreadLocal loggerTL; + + private Deque openStack = new LinkedList<>(); + private boolean open = false; + private int level = 0; private static final PrintStream out; static { + if (ENABLED) { + loggerTL = new ThreadLocal() { + @Override + protected Logger initialValue() { + return new Logger(); + } + }; + } else { + loggerTL = null; + } + + PrintStream ps = null; String filename = System.getProperty("graal.info_file"); if (filename != null && !"".equals(filename)) { @@ -70,12 +84,13 @@ public static void log(String message) { if (ENABLED) { + Logger logger = loggerTL.get(); for (String line : message.split("\n")) { - if (open) { + if (logger.open) { System.out.println("..."); - open = false; + logger.open = false; } - System.out.print(space(level)); + System.out.print(space(logger.level)); System.out.println(line); } } @@ -83,27 +98,29 @@ public static void startScope(String message) { if (ENABLED) { - if (open) { + Logger logger = loggerTL.get(); + if (logger.open) { System.out.println("..."); - open = false; + logger.open = false; } - System.out.print(space(level)); + System.out.print(space(logger.level)); System.out.print(message); - openStack.push(open); - open = true; - level++; + logger.openStack.push(logger.open); + logger.open = true; + logger.level++; } } public static void endScope(String message) { if (ENABLED) { - level--; - if (open) { + Logger logger = loggerTL.get(); + logger.level--; + if (logger.open) { System.out.println(message); } else { - System.out.println(space(level) + "..." + message); + System.out.println(space(logger.level) + "..." + message); } - open = openStack.pop(); + logger.open = logger.openStack.pop(); } } @@ -147,7 +164,7 @@ } return value + " (0x" + Integer.toHexString((Integer) value) + ")"; } else if (value instanceof Long) { - if ((Long) value < 10) { + if ((Long) value < 10 && (Long) value > -10) { return value + "l"; } return value + "l (0x" + Long.toHexString((Long) value) + "l)"; @@ -158,10 +175,19 @@ dimensions++; klass = klass.getComponentType(); } - str.append(klass.getSimpleName()).append('[').append(Array.getLength(value)).append(']'); + int length = Array.getLength(value); + str.append(klass.getSimpleName()).append('[').append(length).append(']'); for (int i = 1; i < dimensions; i++) { str.append("[]"); } + str.append(" {"); + for (int i = 0; i < length; i++) { + str.append(pretty(Array.get(value, i))); + if (i < length - 1) { + str.append(", "); + } + } + str.append('}'); return str.toString(); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotCompiledMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotCompiledMethod.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotCompiledMethod.java Fri Apr 20 13:44:06 2012 +0200 @@ -67,4 +67,24 @@ assert !Modifier.isStatic(method.accessFlags()) || method.signature().argumentKindAt(2, false) == CiKind.Object; return compiler.getVMEntries().executeCompiledMethod(this, arg1, arg2, arg3); } + + private boolean checkArgs(Object... args) { + CiKind[] sig = CiUtil.signatureToKinds(method); + assert args.length == sig.length : CiUtil.format("%H.%n(%p): expected ", method) + sig.length + " args, got " + args.length; + for (int i = 0; i < sig.length; i++) { + Object arg = args[i]; + if (arg == null) { + assert sig[i].isObject() : CiUtil.format("%H.%n(%p): expected arg ", method) + i + " to be Object, not " + sig[i]; + } else if (!sig[i].isObject()) { + assert sig[i].toUnboxedJavaClass() == arg.getClass() : CiUtil.format("%H.%n(%p): expected arg ", method) + i + " to be " + sig[i] + ", not " + arg.getClass(); + } + } + return true; + } + + @Override + public Object executeVarargs(Object... args) { + assert checkArgs(args); + return compiler.getVMEntries().executeCompiledMethodVarargs(this, args); + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Fri Apr 20 13:44:06 2012 +0200 @@ -155,7 +155,12 @@ @Override public StackTraceElement toStackTraceElement(int bci) { - return CiUtil.toStackTraceElement(this, bci); + if (bci < 0 || bci >= codeSize) { + // HotSpot code can only construct stack trace elements for valid bcis + StackTraceElement ste = compiler.getVMEntries().RiMethod_toStackTraceElement(this, 0); + return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); + } + return compiler.getVMEntries().RiMethod_toStackTraceElement(this, bci); } @Override @@ -357,9 +362,6 @@ public boolean canBeInlined() { return canBeInlined; } - public void neverInline() { - this.canBeInlined = false; - } @Override public int vtableEntryOffset() { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRegisterConfig.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRegisterConfig.java Fri Apr 20 13:44:06 2012 +0200 @@ -66,14 +66,7 @@ private final CiRegister[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; private final CiRegister[] allParameterRegisters; - private final CiRegister[] rsaRegs = { - rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, - r8, r9, r10, r11, r12, r13, r14, r15, - xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, - xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 - }; - - private final CiCalleeSaveLayout registerSaveArea; + private final CiCalleeSaveLayout csl; public HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) { if (config.windowsOs) { @@ -83,9 +76,20 @@ } if (globalStubConfig) { - registerSaveArea = new CiCalleeSaveLayout(0, -1, 8, rsaRegs); + CiRegister[] regs = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + csl = new CiCalleeSaveLayout(0, -1, 8, regs); } else { - registerSaveArea = new CiCalleeSaveLayout(0, 8, 8, new CiRegister[0]); + // We reserve space for saving RBP but don't explicitly specify + // it as a callee save register since we explicitly do the saving + // with push and pop in HotSpotFrameContext + final int size = 8; + final CiRegister[] regs = {}; + csl = new CiCalleeSaveLayout(0, size, 8, regs); } attributesMap = RiRegisterAttributes.createMap(this, AMD64.allRegisters); @@ -191,7 +195,7 @@ } public CiCalleeSaveLayout getCalleeSaveLayout() { - return registerSaveArea; + return csl; } @Override diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Fri Apr 20 13:44:06 2012 +0200 @@ -30,21 +30,23 @@ import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.cri.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.Compiler; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.target.amd64.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.snippets.nodes.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ci.CiTargetMethod.Call; import com.oracle.max.cri.ci.CiTargetMethod.DataPatch; +import com.oracle.max.cri.ci.CiTargetMethod.Mark; import com.oracle.max.cri.ci.CiTargetMethod.Safepoint; import com.oracle.max.cri.ci.CiUtil.RefMapFormatter; import com.oracle.max.cri.ri.*; @@ -55,7 +57,7 @@ * CRI runtime implementation for the HotSpot VM. */ public class HotSpotRuntime implements GraalRuntime { - final HotSpotVMConfig config; + public final HotSpotVMConfig config; final HotSpotRegisterConfig regConfig; private final HotSpotRegisterConfig globalStubRegConfig; private final Compiler compiler; @@ -65,6 +67,8 @@ this.compiler = compiler; regConfig = new HotSpotRegisterConfig(config, false); globalStubRegConfig = new HotSpotRegisterConfig(config, true); + + System.setProperty(Backend.BACKEND_CLASS_PROPERTY, HotSpotAMD64Backend.class.getName()); } @Override @@ -82,6 +86,44 @@ return compiler.getVMEntries().disassembleNative(code, address); } + /** + * Decodes a call target to a mnemonic if possible. + */ + private String getTargetName(Call call) { + Field[] fields = config.getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().endsWith("Stub")) { + f.setAccessible(true); + try { + if (f.get(config).equals(call.target)) { + return f.getName(); + } + } catch (Exception e) { + } + } + } + return String.valueOf(call.target); + } + + /** + * Decodes a mark to a mnemonic if possible. + */ + private static String getMarkName(Mark mark) { + Field[] fields = HotSpotXirGenerator.class.getDeclaredFields(); + for (Field f : fields) { + if (Modifier.isStatic(f.getModifiers()) && f.getName().startsWith("MARK_")) { + f.setAccessible(true); + try { + if (f.get(null).equals(mark.id)) { + return f.getName(); + } + } catch (Exception e) { + } + } + } + return "MARK:" + mark.id; + } + @Override public String disassemble(CiTargetMethod tm) { byte[] code = Arrays.copyOf(tm.targetCode(), tm.targetCodeSize()); @@ -97,7 +139,7 @@ if (call.debugInfo != null) { hcf.addComment(call.pcOffset + call.size, CiUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); } - addOperandComment(hcf, call.pcOffset, "{" + call.target + "}"); + addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}"); } else { if (safepoint.debugInfo != null) { hcf.addComment(safepoint.pcOffset, CiUtil.append(new StringBuilder(100), safepoint.debugInfo, slotFormatter).toString()); @@ -108,6 +150,9 @@ for (DataPatch site : tm.dataReferences) { hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}"); } + for (Mark mark : tm.marks) { + hcf.addComment(mark.pcOffset, getMarkName(mark)); + } return hcf.toEmbeddedString(); } @@ -120,6 +165,8 @@ append(e.pcOffset).append(" -> "). append(e.handlerPos). append(nl); + hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); + hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); } hcf.addComment(0, buf.toString()); } @@ -268,7 +315,7 @@ graph.addAfterFixed(cas, writeBarrier); } else { // This may be an array store so use an array write barrier - LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), 0, cas.offset(), graph, false); + LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, false); graph.addAfterFixed(cas, graph.add(new ArrayWriteBarrier(cas.object(), location))); } } @@ -305,10 +352,9 @@ AnchorNode anchor = graph.add(new AnchorNode()); graph.addBeforeFixed(storeIndexed, anchor); GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID); - ReadNode arrayClass = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull())); + FloatingReadNode arrayClass = graph.unique(new FloatingReadNode(array, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull())); arrayClass.setGuard(guard); - graph.addBeforeFixed(storeIndexed, arrayClass); - ReadNode arrayElementKlass = graph.add(new ReadNode(arrayClass, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), StampFactory.objectNonNull())); + FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), StampFactory.objectNonNull())); value = graph.unique(new CheckCastNode(anchor, arrayElementKlass, null, value)); } } @@ -334,19 +380,20 @@ IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph); location.setIndexScalingEnabled(false); WriteNode write = graph.add(new WriteNode(store.object(), store.value(), location)); - FieldWriteBarrier barrier = graph.add(new FieldWriteBarrier(store.object())); write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); - graph.addBeforeFixed(write, barrier); - } else if (n instanceof ArrayHeaderSizeNode) { - ArrayHeaderSizeNode arrayHeaderSize = (ArrayHeaderSizeNode) n; - graph.replaceFloating(arrayHeaderSize, ConstantNode.forLong(config.getArrayOffset(arrayHeaderSize.elementKind()), n.graph())); + if (write.value().kind() == CiKind.Object && !write.value().isNullConstant()) { + FieldWriteBarrier barrier = graph.add(new FieldWriteBarrier(write.object())); + graph.addBeforeFixed(write, barrier); + } } else if (n instanceof ReadHubNode) { ReadHubNode objectClassNode = (ReadHubNode) n; LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph); ReadNode memoryRead = graph.add(new ReadNode(objectClassNode.object(), location, StampFactory.objectNonNull())); memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID)); graph.replaceFixed(objectClassNode, memoryRead); + } else { + assert false : "Node implementing Lowerable not handled: " + n; } } @@ -389,7 +436,7 @@ SafeReadNode klassOop = safeRead(graph, CiKind.Object, receiver, config.klassOopOffset, StampFactory.objectNonNull(), StructuredGraph.INVALID_GRAPH_ID); graph.start().setNext(klassOop); // TODO(thomaswue): Care about primitive classes! Crashes for primitive classes at the moment (klassOop == null) - ReadNode result = graph.add(new ReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Int, config.klassModifierFlagsOffset, graph), StampFactory.forKind(CiKind.Int))); + FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Int, config.klassModifierFlagsOffset, graph), StampFactory.forKind(CiKind.Int))); ReturnNode ret = graph.add(new ReturnNode(result)); klassOop.setNext(ret); return graph; diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java Fri Apr 20 13:44:06 2012 +0200 @@ -23,10 +23,8 @@ package com.oracle.graal.hotspot.ri; import static com.oracle.graal.hotspot.ri.TemplateFlag.*; -import static com.oracle.max.cri.ci.CiCallingConvention.Type.*; import static com.oracle.max.cri.ci.CiValueUtil.*; -import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; @@ -49,25 +47,25 @@ // this needs to correspond to graal_CodeInstaller.hpp // @formatter:off - private static final Integer MARK_VERIFIED_ENTRY = 0x0001; - private static final Integer MARK_UNVERIFIED_ENTRY = 0x0002; - private static final Integer MARK_OSR_ENTRY = 0x0003; - private static final Integer MARK_UNWIND_ENTRY = 0x0004; - private static final Integer MARK_EXCEPTION_HANDLER_ENTRY = 0x0005; - private static final Integer MARK_DEOPT_HANDLER_ENTRY = 0x0006; + public static final Integer MARK_VERIFIED_ENTRY = 0x0001; + public static final Integer MARK_UNVERIFIED_ENTRY = 0x0002; + public static final Integer MARK_OSR_ENTRY = 0x0003; + public static final Integer MARK_UNWIND_ENTRY = 0x0004; + public static final Integer MARK_EXCEPTION_HANDLER_ENTRY = 0x0005; + public static final Integer MARK_DEOPT_HANDLER_ENTRY = 0x0006; - private static final Integer MARK_STATIC_CALL_STUB = 0x1000; + public static final Integer MARK_STATIC_CALL_STUB = 0x1000; - private static final Integer MARK_INVOKEINTERFACE = 0x2001; - private static final Integer MARK_INVOKESTATIC = 0x2002; - private static final Integer MARK_INVOKESPECIAL = 0x2003; - private static final Integer MARK_INVOKEVIRTUAL = 0x2004; + public static final Integer MARK_INVOKEINTERFACE = 0x2001; + public static final Integer MARK_INVOKESTATIC = 0x2002; + public static final Integer MARK_INVOKESPECIAL = 0x2003; + public static final Integer MARK_INVOKEVIRTUAL = 0x2004; - private static final Integer MARK_IMPLICIT_NULL = 0x3000; - private static final Integer MARK_POLL_NEAR = 0x3001; - private static final Integer MARK_POLL_RETURN_NEAR = 0x3002; - private static final Integer MARK_POLL_FAR = 0x3003; - private static final Integer MARK_POLL_RETURN_FAR = 0x3004; + public static final Integer MARK_IMPLICIT_NULL = 0x3000; + public static final Integer MARK_POLL_NEAR = 0x3001; + public static final Integer MARK_POLL_RETURN_NEAR = 0x3002; + public static final Integer MARK_POLL_FAR = 0x3003; + public static final Integer MARK_POLL_RETURN_FAR = 0x3004; // @formatter:on @@ -104,134 +102,6 @@ } } - private SimpleTemplates prologueTemplates = new SimpleTemplates(STATIC_METHOD) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - XirOperand framePointer = asm.createRegisterTemp("frame pointer", target.wordKind, AMD64.rbp); - XirOperand stackPointer = asm.createRegisterTemp("stack pointer", target.wordKind, AMD64.rsp); - XirLabel unverifiedStub = null; - - asm.mark(MARK_OSR_ENTRY); - asm.mark(MARK_UNVERIFIED_ENTRY); - if (!is(STATIC_METHOD, flags)) { - unverifiedStub = asm.createOutOfLineLabel("unverified"); - - XirOperand temp = asm.createRegisterTemp("temp (r10)", target.wordKind, AMD64.r10); - XirOperand cache = asm.createRegisterTemp("cache (rax)", target.wordKind, AMD64.rax); - - CiCallingConvention conventions = registerConfig.getCallingConvention(JavaCallee, new CiKind[] {CiKind.Object}, target, false); - XirOperand receiver = asm.createRegister("receiver", target.wordKind, asRegister(conventions.locations[0])); - - asm.pload(target.wordKind, temp, receiver, asm.i(config.hubOffset), false); - asm.jneq(unverifiedStub, cache, temp); - } - asm.align(config.codeEntryAlignment); - asm.mark(MARK_VERIFIED_ENTRY); - asm.stackOverflowCheck(); - asm.push(framePointer); - asm.mov(framePointer, stackPointer); - // Compensate for the push of framePointer (the XIR instruction pushFrame is not flexible enough to reduce the frame size, wait until XIR goes away to fix this). - asm.add(stackPointer, stackPointer, asm.i(8)); - asm.pushFrame(); - - // -- out of line ------------------------------------------------------- - XirOperand thread = asm.createRegisterTemp("thread", target.wordKind, AMD64.r15); - XirOperand exceptionOop = asm.createTemp("exception oop", CiKind.Object); - XirLabel unwind = asm.createOutOfLineLabel("unwind"); - asm.bindOutOfLine(unwind); - - asm.mark(MARK_UNWIND_ENTRY); - - asm.pload(CiKind.Object, exceptionOop, thread, asm.i(config.threadExceptionOopOffset), false); - asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.createConstant(CiConstant.NULL_OBJECT), false); - asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false); - - asm.callRuntime(config.unwindExceptionStub, null, exceptionOop); - asm.shouldNotReachHere(); - - asm.mark(MARK_EXCEPTION_HANDLER_ENTRY); - asm.callRuntime(config.handleExceptionStub, null); - asm.shouldNotReachHere(); - - asm.mark(MARK_DEOPT_HANDLER_ENTRY); - asm.callRuntime(config.handleDeoptStub, null); - asm.shouldNotReachHere(); - - if (!is(STATIC_METHOD, flags)) { - asm.bindOutOfLine(unverifiedStub); - asm.jmpRuntime(config.inlineCacheMissStub); - } - - return asm.finishTemplate(is(STATIC_METHOD, flags) ? "static prologue" : "prologue"); - } - }; - - private SimpleTemplates epilogueTemplates = new SimpleTemplates(STATIC_METHOD, SYNCHRONIZED) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - XirOperand framePointer = asm.createRegisterTemp("frame pointer", target.wordKind, AMD64.rbp); - XirOperand stackPointer = asm.createRegisterTemp("stack pointer", target.wordKind, AMD64.rsp); - - asm.popFrame(); - asm.pload(CiKind.Long, framePointer, stackPointer, asm.i(-8), false); - - if (GraalOptions.GenSafepoints) { - XirOperand temp = asm.createRegisterTemp("temp", target.wordKind, AMD64.r10); - if (config.isPollingPageFar) { - asm.mov(temp, wordConst(asm, config.safepointPollingAddress)); - asm.mark(MARK_POLL_RETURN_FAR); - asm.pload(target.wordKind, temp, temp, true); - } else { - XirOperand rip = asm.createRegister("rip", target.wordKind, AMD64.rip); - asm.mark(MARK_POLL_RETURN_NEAR); - asm.pload(target.wordKind, temp, rip, asm.i(0xEFBEADDE), true); - } - } - - return asm.finishTemplate("epilogue"); - } - }; - - private SimpleTemplates safepointTemplates = new SimpleTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - - XirOperand temp = asm.createRegisterTemp("temp", target.wordKind, AMD64.r10); - if (config.isPollingPageFar) { - asm.mov(temp, wordConst(asm, config.safepointPollingAddress)); - asm.mark(MARK_POLL_FAR); - asm.pload(target.wordKind, temp, temp, true); - } else { - XirOperand rip = asm.createRegister("rip", target.wordKind, AMD64.rip); - asm.mark(MARK_POLL_NEAR); - asm.pload(target.wordKind, temp, rip, asm.i(0xEFBEADDE), true); - } - - return asm.finishTemplate("safepoint"); - } - }; - - private SimpleTemplates exceptionObjectTemplates = new SimpleTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Object); - XirOperand thread = asm.createRegisterTemp("thread", target.wordKind, AMD64.r15); - - asm.pload(CiKind.Object, result, thread, asm.i(config.threadExceptionOopOffset), false); - asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.o(null), false); - asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false); - - return asm.finishTemplate("exception object"); - } - }; - private SimpleTemplates invokeInterfaceTemplates = new SimpleTemplates(NULL_CHECK) { @Override @@ -958,27 +828,6 @@ }; @Override - public XirSnippet genPrologue(XirSite site, RiResolvedMethod method) { - boolean staticMethod = Modifier.isStatic(method.accessFlags()); - return new XirSnippet(staticMethod ? prologueTemplates.get(site, STATIC_METHOD) : prologueTemplates.get(site)); - } - - @Override - public XirSnippet genEpilogue(XirSite site, RiResolvedMethod method) { - return new XirSnippet(epilogueTemplates.get(site)); - } - - @Override - public XirSnippet genSafepointPoll(XirSite site) { - return new XirSnippet(safepointTemplates.get(site)); - } - - @Override - public XirSnippet genExceptionObject(XirSite site) { - return new XirSnippet(exceptionObjectTemplates.get(site)); - } - - @Override public XirSnippet genInvokeInterface(XirSite site, XirArgument receiver, RiMethod method) { return new XirSnippet(invokeInterfaceTemplates.get(site), receiver, wordArg(0)); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Fri Apr 20 13:44:06 2012 +0200 @@ -21,16 +21,15 @@ * questions. */ package com.oracle.graal.hotspot.snippets; -import com.oracle.max.cri.ci.*; import com.oracle.graal.cri.*; -import com.oracle.graal.graph.Node.Fold; +import com.oracle.graal.graph.Node.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.nodes.*; +import com.oracle.max.cri.ci.*; public class ArrayCopySnippets implements SnippetsInterface{ @@ -228,7 +227,7 @@ copyObjectsUp(src, srcPos * 8L, dest, destPos * 8L, length); } if (length > 0) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Object); + int header = arrayHeaderSizeFor(CiKind.Object); int cardShift = cardTableShift(); long cardStart = cardTableStart(); long dstAddr = GetObjectAddressNode.get(dest); @@ -243,47 +242,47 @@ @Snippet public static void copyBytesDown(Object src, int srcPos, Object dest, int destPos, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Byte); + int header = arrayHeaderSizeFor(CiKind.Byte); for (long i = length - 1; i >= 0; i--) { - Byte a = UnsafeLoadNode.load(src, i + (srcPos + header), CiKind.Byte); - UnsafeStoreNode.store(dest, i + (destPos + header), a.byteValue(), CiKind.Byte); + Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte); + UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte); } } @Snippet public static void copyShortsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Short); + int header = arrayHeaderSizeFor(CiKind.Short); for (long i = (length - 1) * 2; i >= 0; i -= 2) { - Character a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Short); - UnsafeStoreNode.store(dest, i + (destOffset + header), a.charValue(), CiKind.Short); + Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short); + UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short); } } @Snippet public static void copyIntsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Int); + int header = arrayHeaderSizeFor(CiKind.Int); for (long i = (length - 1) * 4; i >= 0; i -= 4) { - Integer a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Int); - UnsafeStoreNode.store(dest, i + (destOffset + header), a.intValue(), CiKind.Int); + Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int); + UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int); } } @Snippet public static void copyLongsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Long); + int header = arrayHeaderSizeFor(CiKind.Long); for (long i = (length - 1) * 8; i >= 0; i -= 8) { - Long a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Long); - UnsafeStoreNode.store(dest, i + (destOffset + header), a.longValue(), CiKind.Long); + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long); } } // Does NOT perform store checks @Snippet public static void copyObjectsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Object); - for (long i = (length - 1) * 8; i >= 0; i -= 8) { - Object a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Object); - DirectObjectStoreNode.store(dest, i + (destOffset + header), a); + int header = arrayHeaderSizeFor(CiKind.Object); + for (long i = (length - 1) * wordSize(); i >= 0; i -= wordSize()) { + Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object); + DirectObjectStoreNode.store(dest, header, i + destOffset, a); } } /** @@ -296,10 +295,10 @@ */ @Snippet public static void copyBytesUp(Object src, int srcPos, Object dest, int destPos, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Byte); + int header = arrayHeaderSizeFor(CiKind.Byte); for (long i = 0; i < length; i++) { - Byte a = UnsafeLoadNode.load(src, i + (srcPos + header), CiKind.Byte); - UnsafeStoreNode.store(dest, i + (destPos + header), a.byteValue(), CiKind.Byte); + Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte); + UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte); } } @@ -313,38 +312,38 @@ */ @Snippet public static void copyShortsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Short); + int header = arrayHeaderSizeFor(CiKind.Short); for (long i = 0; i < length * 2L; i += 2) { - Character a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Short); - UnsafeStoreNode.store(dest, i + (destOffset + header), a.charValue(), CiKind.Short); + Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short); + UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short); } } @Snippet public static void copyIntsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Int); + int header = arrayHeaderSizeFor(CiKind.Int); for (long i = 0; i < length * 4L; i += 4) { - Integer a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Int); - UnsafeStoreNode.store(dest, i + (destOffset + header), a.intValue(), CiKind.Int); + Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int); + UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int); } } @Snippet public static void copyLongsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Long); + int header = arrayHeaderSizeFor(CiKind.Long); for (long i = 0; i < length * 8L; i += 8) { - Long a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Long); - UnsafeStoreNode.store(dest, i + (destOffset + header), a.longValue(), CiKind.Long); + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long); } } // Does NOT perform store checks @Snippet public static void copyObjectsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - long header = ArrayHeaderSizeNode.sizeFor(CiKind.Object); - for (long i = 0; i < length * 8L; i += 8) { - Object a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Object); - DirectObjectStoreNode.store(dest, i + (destOffset + header), a); + int header = arrayHeaderSizeFor(CiKind.Object); + for (long i = 0; i < length * wordSize(); i += wordSize()) { + Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object); + DirectObjectStoreNode.store(dest, header, i + destOffset, a); } } private static class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable { @@ -401,42 +400,42 @@ @Input private ValueNode object; @Input private ValueNode value; @Input private ValueNode offset; + @Data private final int displacement; - public DirectObjectStoreNode(ValueNode object, ValueNode offset, ValueNode value) { + public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) { super(StampFactory.illegal()); this.object = object; this.value = value; this.offset = offset; + this.displacement = displacement; } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object obj, long offset, long value) { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("unused") - @NodeIntrinsic - public static void store(Object obj, long offset, boolean value) { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("unused") - @NodeIntrinsic - public static void store(Object obj, long offset, Object value) { + public static void store(Object obj, @ConstantNodeParameter int displacement, long offset, Object value) { throw new UnsupportedOperationException(); } @Override public void lower(CiLoweringTool tool) { StructuredGraph graph = (StructuredGraph) this.graph(); - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), 0, offset, graph, false); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, false); WriteNode write = graph.add(new WriteNode(object, value, location)); graph.replaceFixedWithFixed(this, write); } } @Fold + private static int wordSize() { + return CompilerImpl.getInstance().getTarget().wordSize; + } + + @Fold + private static int arrayHeaderSizeFor(CiKind elementKind) { + return CompilerImpl.getInstance().getConfig().getArrayOffset(elementKind); + } + + @Fold private static int cardTableShift() { return CompilerImpl.getInstance().getConfig().cardtableShift; } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/UnsafeSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/UnsafeSnippets.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/UnsafeSnippets.java Fri Apr 20 13:44:06 2012 +0200 @@ -35,19 +35,19 @@ public class UnsafeSnippets implements SnippetsInterface { public boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) { - return CompareAndSwapNode.compareAndSwap(o, offset, expected, x); + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); } public boolean compareAndSwapInt(Object o, long offset, int expected, int x) { - return CompareAndSwapNode.compareAndSwap(o, offset, expected, x); + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); } public boolean compareAndSwapLong(Object o, long offset, long expected, long x) { - return CompareAndSwapNode.compareAndSwap(o, offset, expected, x); + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); } public Object getObject(Object o, long offset) { - return UnsafeLoadNode.load(o, offset, CiKind.Object); + return UnsafeLoadNode.load(o, 0, offset, CiKind.Object); } public Object getObjectVolatile(Object o, long offset) { @@ -58,7 +58,7 @@ } public void putObject(Object o, long offset, Object x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Object); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Object); } public void putObjectVolatile(Object o, long offset, Object x) { @@ -68,7 +68,7 @@ } public int getInt(Object o, long offset) { - Integer value = UnsafeLoadNode.load(o, offset, CiKind.Int); + Integer value = UnsafeLoadNode.load(o, 0, offset, CiKind.Int); return value; } @@ -80,7 +80,7 @@ } public void putInt(Object o, long offset, int x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Int); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Int); } public void putIntVolatile(Object o, long offset, int x) { @@ -91,7 +91,7 @@ public boolean getBoolean(Object o, long offset) { @JavacBug(id = 6995200) - Boolean result = UnsafeLoadNode.load(o, offset, CiKind.Boolean); + Boolean result = UnsafeLoadNode.load(o, 0, offset, CiKind.Boolean); return result; } @@ -103,7 +103,7 @@ } public void putBoolean(Object o, long offset, boolean x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Boolean); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Boolean); } public void putBooleanVolatile(Object o, long offset, boolean x) { @@ -114,7 +114,7 @@ public byte getByte(Object o, long offset) { @JavacBug(id = 6995200) - Byte result = UnsafeLoadNode.load(o, offset, CiKind.Byte); + Byte result = UnsafeLoadNode.load(o, 0, offset, CiKind.Byte); return result; } @@ -126,7 +126,7 @@ } public void putByte(Object o, long offset, byte x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Byte); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Byte); } public void putByteVolatile(Object o, long offset, byte x) { @@ -137,7 +137,7 @@ public short getShort(Object o, long offset) { @JavacBug(id = 6995200) - Short result = UnsafeLoadNode.load(o, offset, CiKind.Short); + Short result = UnsafeLoadNode.load(o, 0, offset, CiKind.Short); return result; } @@ -149,7 +149,7 @@ } public void putShort(Object o, long offset, short x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Short); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Short); } public void putShortVolatile(Object o, long offset, short x) { @@ -160,7 +160,7 @@ public char getChar(Object o, long offset) { @JavacBug(id = 6995200) - Character result = UnsafeLoadNode.load(o, offset, CiKind.Char); + Character result = UnsafeLoadNode.load(o, 0, offset, CiKind.Char); return result; } @@ -172,7 +172,7 @@ } public void putChar(Object o, long offset, char x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Char); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Char); } public void putCharVolatile(Object o, long offset, char x) { @@ -183,7 +183,7 @@ public long getLong(Object o, long offset) { @JavacBug(id = 6995200) - Long result = UnsafeLoadNode.load(o, offset, CiKind.Long); + Long result = UnsafeLoadNode.load(o, 0, offset, CiKind.Long); return result; } @@ -195,7 +195,7 @@ } public void putLong(Object o, long offset, long x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Long); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Long); } public void putLongVolatile(Object o, long offset, long x) { @@ -206,7 +206,7 @@ public float getFloat(Object o, long offset) { @JavacBug(id = 6995200) - Float result = UnsafeLoadNode.load(o, offset, CiKind.Float); + Float result = UnsafeLoadNode.load(o, 0, offset, CiKind.Float); return result; } @@ -218,7 +218,7 @@ } public void putFloat(Object o, long offset, float x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Float); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Float); } public void putFloatVolatile(Object o, long offset, float x) { @@ -229,7 +229,7 @@ public double getDouble(Object o, long offset) { @JavacBug(id = 6995200) - Double result = UnsafeLoadNode.load(o, offset, CiKind.Double); + Double result = UnsafeLoadNode.load(o, 0, offset, CiKind.Double); return result; } @@ -241,7 +241,7 @@ } public void putDouble(Object o, long offset, double x) { - UnsafeStoreNode.store(o, offset, x, CiKind.Double); + UnsafeStoreNode.store(o, 0, offset, x, CiKind.Double); } public void putDoubleVolatile(Object o, long offset, double x) { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64SafepointOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64SafepointOp.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,70 @@ +/* + * 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.hotspot.target.amd64; + +import static com.oracle.graal.hotspot.ri.HotSpotXirGenerator.*; +import static com.oracle.max.asm.target.amd64.AMD64.*; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; + +/** + * Emits a safepoint poll. + */ +public class AMD64SafepointOp extends AMD64LIRInstruction { + + private final HotSpotVMConfig config; + + public AMD64SafepointOp(LIRDebugInfo info, HotSpotVMConfig config) { + super("SAFEPOINT", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + this.config = config; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler asm) { + CiRegister scratch = tasm.frameMap.registerConfig.getScratchRegister(); + int pos = asm.codeBuffer.position(); + if (config.isPollingPageFar) { + asm.movq(scratch, config.safepointPollingAddress); + tasm.recordMark(MARK_POLL_FAR); + tasm.recordSafepoint(pos, info); + asm.movq(scratch, new CiAddress(tasm.target.wordKind, scratch.asValue())); + } else { + tasm.recordMark(MARK_POLL_NEAR); + tasm.recordSafepoint(pos, info); + asm.movq(scratch, new CiAddress(tasm.target.wordKind, rip.asValue())); + } + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + throw GraalInternalError.shouldNotReachHere(); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,241 @@ +/* + * 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.hotspot.target.amd64; + +import static com.oracle.graal.hotspot.ri.HotSpotXirGenerator.*; +import static com.oracle.max.asm.target.amd64.AMD64.*; +import static com.oracle.max.cri.ci.CiCallingConvention.Type.*; +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.lang.reflect.*; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.compiler.target.amd64.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.ri.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiCallingConvention.Type; +import com.oracle.max.cri.ci.CiRegister.RegisterFlag; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.xir.*; + +public class HotSpotAMD64Backend extends Backend { + + public HotSpotAMD64Backend(RiRuntime runtime, CiTarget target) { + super(runtime, target); + } + + @Override + public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) { + return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir) { + @Override + public void visitLoopEnd(LoopEndNode x) { + if (GraalOptions.GenLoopSafepoints && x.hasSafepointPolling()) { + LIRDebugInfo info = state(); + if (!info.topFrame.method.noSafepointPolls()) { + append(new AMD64SafepointOp(info, ((HotSpotRuntime) runtime).config)); + } + } + } + @Override + public void visitExceptionObject(ExceptionObjectNode x) { + HotSpotVMConfig config = ((HotSpotRuntime) runtime).config; + CiRegisterValue thread = r15.asValue(); + CiAddress exceptionAddress = new CiAddress(CiKind.Object, thread, config.threadExceptionOopOffset); + CiAddress pcAddress = new CiAddress(CiKind.Long, thread, config.threadExceptionPcOffset); + CiValue exception = emitLoad(exceptionAddress, false); + emitStore(exceptionAddress, CiConstant.NULL_OBJECT, false); + emitStore(pcAddress, CiConstant.LONG_0, false); + setResult(x, exception); + } + }; + } + + @Override + public AMD64XirAssembler newXirAssembler() { + return new AMD64XirAssembler(target); + } + + class HotSpotFrameContext implements FrameContext { + + @Override + public void enter(TargetMethodAssembler tasm) { + FrameMap frameMap = tasm.frameMap; + int frameSize = frameMap.frameSize(); + + AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; + emitStackOverflowCheck(tasm, false); + asm.push(rbp); + asm.movq(rbp, rsp); + asm.decrementq(rsp, frameSize - 8); // account for the push of RBP above + if (GraalOptions.ZapStackOnMethodEntry) { + final int intSize = 4; + for (int i = 0; i < frameSize / intSize; ++i) { + asm.movl(new CiAddress(CiKind.Int, rsp.asValue(), i * intSize), 0xC1C1C1C1); + } + } + CiCalleeSaveLayout csl = frameMap.registerConfig.getCalleeSaveLayout(); + if (csl != null && csl.size != 0) { + int frameToCSA = frameMap.offsetToCalleeSaveArea(); + assert frameToCSA >= 0; + asm.save(csl, frameToCSA); + } + } + + @Override + public void leave(TargetMethodAssembler tasm) { + int frameSize = tasm.frameMap.frameSize(); + AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; + CiCalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout(); + RiRegisterConfig regConfig = tasm.frameMap.registerConfig; + + if (csl != null && csl.size != 0) { + tasm.targetMethod.setRegisterRestoreEpilogueOffset(asm.codeBuffer.position()); + // saved all registers, restore all registers + int frameToCSA = tasm.frameMap.offsetToCalleeSaveArea(); + asm.restore(csl, frameToCSA); + } + + asm.incrementq(rsp, frameSize - 8); // account for the pop of RBP below + asm.pop(rbp); + + if (GraalOptions.GenSafepoints) { + HotSpotVMConfig config = ((HotSpotRuntime) runtime).config; + + // If at the return point, then the frame has already been popped + // so deoptimization cannot be performed here. The HotSpot runtime + // detects this case - see the definition of frame::should_be_deoptimized() + + CiRegister scratch = regConfig.getScratchRegister(); + if (config.isPollingPageFar) { + asm.movq(scratch, config.safepointPollingAddress); + tasm.recordMark(MARK_POLL_RETURN_FAR); + asm.movq(scratch, new CiAddress(tasm.target.wordKind, scratch.asValue())); + } else { + tasm.recordMark(MARK_POLL_RETURN_NEAR); + asm.movq(scratch, new CiAddress(tasm.target.wordKind, rip.asValue())); + } + } + } + } + + @Override + public TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir) { + // Omit the frame if the method: + // - has no spill slots or other slots allocated during register allocation + // - has no callee-saved registers + // - has no incoming arguments passed on the stack + // - has no instructions with debug info + boolean canOmitFrame = + frameMap.frameSize() == frameMap.initialFrameSize && + frameMap.registerConfig.getCalleeSaveLayout().registers.length == 0 && + !lir.hasArgInCallerFrame() && + !lir.hasDebugInfo(); + + AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig); + HotSpotFrameContext frameContext = canOmitFrame ? null : new HotSpotFrameContext(); + TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime, frameMap, masm, frameContext); + tasm.setFrameSize(frameMap.frameSize()); + tasm.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea()); + return tasm; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, RiResolvedMethod method, LIR lir) { + AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; + FrameMap frameMap = tasm.frameMap; + RiRegisterConfig regConfig = frameMap.registerConfig; + HotSpotVMConfig config = ((HotSpotRuntime) runtime).config; + Label unverifiedStub = new Label(); + + // Emit the prefix + tasm.recordMark(MARK_OSR_ENTRY); + tasm.recordMark(MARK_UNVERIFIED_ENTRY); + + boolean isStatic = Modifier.isStatic(method.accessFlags()); + if (!isStatic) { + CiCallingConvention cc = regConfig.getCallingConvention(JavaCallee, new CiKind[] {CiKind.Object}, target, false); + CiRegister inlineCacheKlass = rax; // see definition of IC_Klass in c1_LIRAssembler_x86.cpp + CiRegister receiver = asRegister(cc.locations[0]); + CiAddress src = new CiAddress(target.wordKind, receiver.asValue(), config.hubOffset); + + asm.cmpq(inlineCacheKlass, src); + asm.jcc(ConditionFlag.notEqual, unverifiedStub); + } + + asm.align(config.codeEntryAlignment); + tasm.recordMark(MARK_VERIFIED_ENTRY); + + // Emit code for the LIR + lir.emitCode(tasm); + + boolean frameOmitted = tasm.frameContext == null; + if (!frameOmitted) { + CiRegister thread = r15; + CiRegister exceptionOop = regConfig.getCallingConventionRegisters(Type.RuntimeCall, RegisterFlag.CPU)[0]; + Label unwind = new Label(); + asm.bind(unwind); + tasm.recordMark(MARK_UNWIND_ENTRY); + CiAddress exceptionOopField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionOopOffset); + CiAddress exceptionPcField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionPcOffset); + asm.movq(exceptionOop, exceptionOopField); + asm.movslq(exceptionOopField, 0); + asm.movslq(exceptionPcField, 0); + + AMD64Call.directCall(tasm, asm, config.unwindExceptionStub, null); + AMD64Call.shouldNotReachHere(tasm, asm); + + tasm.recordMark(MARK_EXCEPTION_HANDLER_ENTRY); + AMD64Call.directCall(tasm, asm, config.handleExceptionStub, null); + AMD64Call.shouldNotReachHere(tasm, asm); + + tasm.recordMark(MARK_DEOPT_HANDLER_ENTRY); + AMD64Call.directCall(tasm, asm, config.handleDeoptStub, null); + AMD64Call.shouldNotReachHere(tasm, asm); + } else { + // No need to emit the stubs for entries back into the method since + // it has no calls that can cause such "return" entries + assert !frameMap.accessesCallerFrame(); + } + + if (!isStatic) { + asm.bind(unverifiedStub); + AMD64Call.directJmp(tasm, asm, config.inlineCacheMissStub); + } + + for (int i = 0; i < GraalOptions.MethodEndBreakpointGuards; ++i) { + asm.int3(); + } + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Fri Apr 20 13:44:06 2012 +0200 @@ -121,12 +121,14 @@ public int endBci; public boolean isExceptionEntry; public boolean isLoopHeader; + public int loopId; public int blockID; public FixedWithNextNode firstInstruction; public FrameStateBuilder entryState; public ArrayList successors = new ArrayList<>(2); + public long exits; public int normalSuccessors; private boolean visited; @@ -191,6 +193,7 @@ private final BytecodeStream stream; private final RiExceptionHandler[] exceptionHandlers; private Block[] blockMap; + public Block[] loopHeaders; /** * Creates a new BlockMap instance from bytecode of the given method . @@ -204,6 +207,7 @@ this.blockMap = new Block[method.codeSize()]; this.canTrap = new BitSet(blockMap.length); this.blocks = new ArrayList<>(); + this.loopHeaders = new Block[64]; } public RiExceptionHandler[] exceptionHandlers() { @@ -223,7 +227,11 @@ } createJsrAlternatives(blockMap[0]); } + if (Debug.isLogEnabled()) { + this.log("Before BlockOrder"); + } computeBlockOrder(); + fixLoopBits(); initializeBlockIds(); @@ -231,7 +239,9 @@ // Discard big arrays so that they can be GCed blockMap = null; - + if (Debug.isLogEnabled()) { + this.log("Before LivenessAnalysis"); + } if (GraalOptions.OptLivenessAnalysis) { Debug.scope("LivenessAnalysis", new Runnable() { @Override @@ -541,6 +551,26 @@ } } + private boolean loopChanges; + + private void fixLoopBits() { + do { + loopChanges = false; + for (Block b : blocks) { + b.visited = false; + } + + long loop = fixLoopBits(blockMap[0]); + + if (loop != 0) { + // There is a path from a loop end to the method entry that does not pass the loop header. + // Therefore, the loop is non reducible (has more than one entry). + // We don't want to compile such methods because the IR only supports structured loops. + throw new CiBailout("Non-reducible loop"); + } + } while (loopChanges); + } + private void computeBlockOrder() { long loop = computeBlockOrder(blockMap[0]); @@ -555,6 +585,64 @@ Collections.reverse(blocks); } + public void log(String name) { + if (Debug.isLogEnabled()) { + String n = System.lineSeparator(); + StringBuilder sb = new StringBuilder(Debug.currentScope()).append("BlockMap ").append(name).append(" :"); + sb.append(n); + Iterable it; + if (blocks.isEmpty()) { + it = new HashSet<>(Arrays.asList(blockMap)); + } else { + it = blocks; + } + for (Block b : it) { + if (b == null) { + continue; + } + sb.append("B").append(b.blockID).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")"); + if (b.isLoopHeader) { + sb.append(" LoopHeader"); + } + if (b.isExceptionEntry) { + sb.append(" ExceptionEntry"); + } + sb.append(n).append(" Sux : "); + for (Block s : b.successors) { + sb.append("B").append(s.blockID).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")"); + if (s.isExceptionEntry) { + sb.append("!"); + } + sb.append(" "); + } + sb.append(n).append(" Loop : "); + long l = b.loops; + int pos = 0; + while (l != 0) { + int lMask = 1 << pos; + if ((l & lMask) != 0) { + sb.append("B").append(loopHeaders[pos].blockID).append(" "); + l &= ~lMask; + } + pos++; + } + sb.append(n).append(" Exits : "); + l = b.exits; + pos = 0; + while (l != 0) { + int lMask = 1 << pos; + if ((l & lMask) != 0) { + sb.append("B").append(loopHeaders[pos].blockID).append(" "); + l &= ~lMask; + } + pos++; + } + sb.append(n); + } + Debug.log(sb.toString()); + } + } + /** * The next available loop number. */ @@ -581,6 +669,9 @@ assert block.loops == 0; block.loops = (long) 1 << (long) nextLoop; + Debug.log("makeLoopHeader(%s) -> %x", block, block.loops); + loopHeaders[nextLoop] = block; + block.loopId = nextLoop; nextLoop++; } assert Long.bitCount(block.loops) == 1; @@ -596,9 +687,13 @@ if (block.active) { // Reached block via backward branch. makeLoopHeader(block); + // Return cached loop information for this block. + return block.loops; + } else if (block.isLoopHeader) { + return block.loops & ~(1L << block.loopId); + } else { + return block.loops; } - // Return cached loop information for this block. - return block.loops; } block.visited = true; @@ -610,18 +705,50 @@ loops |= computeBlockOrder(successor); } + block.loops = loops; + Debug.log("computeBlockOrder(%s) -> %x", block, block.loops); + if (block.isLoopHeader) { - assert Long.bitCount(block.loops) == 1; - loops &= ~block.loops; + loops &= ~(1L << block.loopId); } - block.loops = loops; block.active = false; blocks.add(block); return loops; } + private long fixLoopBits(Block block) { + if (block.visited) { + // Return cached loop information for this block. + if (block.isLoopHeader) { + return block.loops & ~(1L << block.loopId); + } else { + return block.loops; + } + } + + block.visited = true; + long loops = block.loops; + for (Block successor : block.successors) { + // Recursively process successors. + loops |= fixLoopBits(successor); + } + for (Block successor : block.successors) { + successor.exits = loops & ~successor.loops; + } + if (block.loops != loops) { + loopChanges = true; + block.loops = loops; + Debug.log("fixLoopBits0(%s) -> %x", block, block.loops); + } + + if (block.isLoopHeader) { + loops &= ~(1L << block.loopId); + } + + return loops; + } private void computeLiveness() { for (Block block : blocks) { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Fri Apr 20 13:44:06 2012 +0200 @@ -28,6 +28,7 @@ import java.util.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; @@ -200,15 +201,40 @@ } // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles). List phiUsages = phi.usages().filter(PhiNode.class).snapshot(); + List vpnUsages = phi.usages().filter(ValueProxyNode.class).snapshot(); // Remove the phi function from all FrameStates where it is used and then delete it. - assert phi.usages().filter(isNotA(FrameState.class).nor(PhiNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + assert phi.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; phi.replaceAtUsages(null); phi.safeDelete(); for (PhiNode phiUsage : phiUsages) { deletePhi(phiUsage); } + for (ValueProxyNode proxyUsage : vpnUsages) { + deleteProxy(proxyUsage); + } + } + + private void deleteProxy(ValueProxyNode proxy) { + if (proxy.isDeleted()) { + return; + } + // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles). + List phiUsages = proxy.usages().filter(PhiNode.class).snapshot(); + List vpnUsages = proxy.usages().filter(ValueProxyNode.class).snapshot(); + + // Remove the proxy function from all FrameStates where it is used and then delete it. + assert proxy.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + proxy.replaceAtUsages(null); + proxy.safeDelete(); + + for (PhiNode phiUsage : phiUsages) { + deletePhi(phiUsage); + } + for (ValueProxyNode proxyUsage : vpnUsages) { + deleteProxy(proxyUsage); + } } public void insertLoopPhis(LoopBeginNode loopBegin) { @@ -220,6 +246,23 @@ } } + public void insertProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = localAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeLocal(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value))); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stackAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeStack(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value))); + } + } + } + private PhiNode createLoopPhi(MergeNode block, ValueNode value) { if (value == null) { return null; @@ -545,4 +588,18 @@ assert kind != CiKind.Void && kind != CiKind.Illegal; return kind == CiKind.Long || kind == CiKind.Double; } + + public boolean contains(ValueNode value) { + for (int i = 0; i < localsSize(); i++) { + if (localAt(i) == value) { + return true; + } + } + for (int i = 0; i < stackSize(); i++) { + if (stackAt(i) == value) { + return true; + } + } + return false; + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Apr 20 13:44:06 2012 +0200 @@ -43,6 +43,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.cri.ri.RiType.Representation; @@ -104,6 +105,8 @@ } } + private Block[] loopHeaders; + public GraphBuilderPhase(RiRuntime runtime, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; @@ -156,6 +159,7 @@ this.canTrapBitSet = blockMap.canTrap; exceptionHandlers = blockMap.exceptionHandlers(); + loopHeaders = blockMap.loopHeaders; lastInstr = currentGraph.start(); if (isSynchronized(method.accessFlags())) { @@ -1197,6 +1201,67 @@ return x; } + private static class Target { + FixedNode fixed; + FrameStateBuilder state; + public Target(FixedNode fixed, FrameStateBuilder state) { + this.fixed = fixed; + this.state = state; + } + } + + private Target checkLoopExit(FixedNode traget, Block targetBlock, FrameStateBuilder state) { + if (currentBlock != null) { + long exits = currentBlock.loops & ~targetBlock.loops; + if (exits != 0) { + LoopExitNode firstLoopExit = null; + LoopExitNode lastLoopExit = null; + + int pos = 0; + ArrayList exitLoops = new ArrayList<>(Long.bitCount(exits)); + do { + int lMask = 1 << pos; + if ((exits & lMask) != 0) { + exitLoops.add(loopHeaders[pos]); + exits &= ~lMask; + } + pos++; + } while (exits != 0); + + Collections.sort(exitLoops, new Comparator() { + @Override + public int compare(Block o1, Block o2) { + return Long.bitCount(o2.loops) - Long.bitCount(o1.loops); + } + }); + + int bci = targetBlock.startBci; + if (targetBlock instanceof ExceptionBlock) { + bci = ((ExceptionBlock) targetBlock).deoptBci; + } + FrameStateBuilder newState = state.copy(); + for (Block loop : exitLoops) { + LoopBeginNode loopBegin = (LoopBeginNode) loop.firstInstruction; + LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin)); + if (lastLoopExit != null) { + lastLoopExit.setNext(loopExit); + } + if (firstLoopExit == null) { + firstLoopExit = loopExit; + } + lastLoopExit = loopExit; + Debug.log("Traget %s (%s) Exits %s, scanning framestates...", targetBlock, traget, loop); + newState.insertProxies(loopExit, loop.entryState); + loopExit.setStateAfter(newState.create(bci)); + } + + lastLoopExit.setNext(traget); + return new Target(firstLoopExit, newState); + } + } + return new Target(traget, state); + } + private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) { assert probability >= 0 && probability <= 1; if (probability == 0 && optimisticOpts.removeNeverExecutedCode()) { @@ -1206,23 +1271,25 @@ } } - private FixedNode createTarget(Block block, FrameStateBuilder stateAfter) { - assert block != null && stateAfter != null; - assert !block.isExceptionEntry || stateAfter.stackSize() == 1; + private FixedNode createTarget(Block block, FrameStateBuilder state) { + assert block != null && state != null; + assert !block.isExceptionEntry || state.stackSize() == 1; if (block.firstInstruction == null) { // This is the first time we see this block as a branch target. // Create and return a placeholder that later can be replaced with a MergeNode when we see this block again. block.firstInstruction = currentGraph.add(new BlockPlaceholderNode()); - block.entryState = stateAfter.copy(); + Target target = checkLoopExit(block.firstInstruction, block, state); + FixedNode result = target.fixed; + block.entryState = target.state == state ? state.copy() : target.state; block.entryState.clearNonLiveLocals(block.localsLiveIn); Debug.log("createTarget %s: first visit, result: %s", block, block.firstInstruction); - return block.firstInstruction; + return result; } // We already saw this block before, so we have to merge states. - if (!block.entryState.isCompatibleWith(stateAfter)) { + if (!block.entryState.isCompatibleWith(state)) { throw new CiBailout("stacks do not match; bytecodes would not verify"); } @@ -1230,8 +1297,9 @@ assert block.isLoopHeader && currentBlock.blockID >= block.blockID : "must be backward branch"; // Backward loop edge. We need to create a special LoopEndNode and merge with the loop begin node created before. LoopBeginNode loopBegin = (LoopBeginNode) block.firstInstruction; - LoopEndNode result = currentGraph.add(new LoopEndNode(loopBegin)); - block.entryState.merge(loopBegin, stateAfter); + Target target = checkLoopExit(currentGraph.add(new LoopEndNode(loopBegin)), block, state); + FixedNode result = target.fixed; + block.entryState.merge(loopBegin, target.state); Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); return result; @@ -1260,9 +1328,11 @@ MergeNode mergeNode = (MergeNode) block.firstInstruction; // The EndNode for the newly merged edge. - EndNode result = currentGraph.add(new EndNode()); - block.entryState.merge(mergeNode, stateAfter); - mergeNode.addForwardEnd(result); + EndNode newEnd = currentGraph.add(new EndNode()); + Target target = checkLoopExit(newEnd, block, state); + FixedNode result = target.fixed; + block.entryState.merge(mergeNode, target.state); + mergeNode.addForwardEnd(newEnd); Debug.log("createTarget %s: merging state, result: %s", block, result); return result; @@ -1274,9 +1344,7 @@ */ private BeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) { FixedNode target = createTarget(probability, block, stateAfter); - assert !(target instanceof BeginNode); - BeginNode begin = currentGraph.add(new BeginNode()); - begin.setNext(target); + BeginNode begin = BeginNode.begin(target); assert !(target instanceof DeoptimizeNode && begin.stateAfter() != null) : "We are not allowed to set the stateAfter of the begin node, because we have to deoptimize to a bci _before_ the actual if, so that the interpreter can update the profiling information."; @@ -1340,25 +1408,7 @@ assert begin.forwardEndCount() == 1; currentGraph.reduceDegenerateLoopBegin(begin); } else { - // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either the same or the phi itself. - for (PhiNode phi : begin.phis().snapshot()) { - checkRedundantPhi(phi); - } - } - } - } - - private static void checkRedundantPhi(PhiNode phiNode) { - if (phiNode.isDeleted() || phiNode.valueCount() == 1) { - return; - } - - ValueNode singleValue = phiNode.singleValue(); - if (singleValue != null) { - Collection phiUsages = phiNode.usages().filter(PhiNode.class).snapshot(); - ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue); - for (PhiNode phi : phiUsages) { - checkRedundantPhi(phi); + GraphUtil.normalizeLoopBegin(begin); } } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop15.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop15.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,64 @@ +/* + * 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.jtt.loop; + +import org.junit.*; + +public class Loop15 { + + public static int test(int arg) { + Object o = null; + int result = 10; + for (int k = 0; k < arg; ++k) { + if (o == null) { + o = new Object(); + } + if (k >= 5) { + break; + } + result++; + } + return result + (o == null ? 0 : 1); + } + + @Test + public void run0() throws Throwable { + Assert.assertEquals(16, test(5)); + } + + @Test + public void run1() throws Throwable { + Assert.assertEquals(10, test(0)); + } + + @Test + public void run2() throws Throwable { + Assert.assertEquals(12, test(1)); + } + + @Test + public void run3() throws Throwable { + Assert.assertEquals(16, test(10)); + } + +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop16.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop16.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 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. + */ +// Checkstyle: stop +package com.oracle.graal.jtt.loop; + +import org.junit.*; + +/* + * Tests exiting 2 loops at the same time with escape-analysed values flowing out of loops + */ +public class Loop16 { + + public int a; + public int b; + public int c; + + public static int test(int count) { + return new Loop16().run(count); + } + + public int run(int count) { + l1: for (int i = 0; i <= count; i++) { + if (i > 5) { + for (int j = 0; j < i; j++) { + a += i; + if (a > 500) { + break l1; + } + } + } else if (i > 7) { + b += i; + } else { + c += i; + } + } + return a + b + c; + } + + @Test + public void run0() throws Throwable { + Assert.assertEquals(526, test(40)); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop17.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop17.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 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. + */ +// Checkstyle: stop +package com.oracle.graal.jtt.loop; + +import org.junit.*; + +/* + * Test around an object that escapes directly from inside a loop (no virtual phi on the loop) + */ +public class Loop17 { + + private static class L { + public int a; + public int b; + public int c; + public L(int a, int b, int c) { + this.a = a; + this.b = b; + this.c = c; + } + } + + + public static int test(int count) { + int i = 0; + L l; + do { + l = new L(i, i+1, i+2); + } while (++i < count); + + return l.a + l.b * 10 + l.c * 100; + } + + @Test + public void run0() throws Throwable { + Assert.assertEquals(543, test(new L(4,4,4).a)); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopLastIndexOf.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopLastIndexOf.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,100 @@ +/* + * 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.jtt.loop; + +import org.junit.*; + +/* + * see java.lang.String.lastIndexOf(char[], int, int, char[], int ,int, int) + */ +public class LoopLastIndexOf { + + private final char[] v1 = new char[]{'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'}; + private final char[] v2 = new char[]{'d', 'a'}; + private final char[] v3 = new char[]{'d', 'b', 'c'}; + private final char[] v4 = new char[]{'z', 'a', 'b', 'c'}; + + public static int test(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { + int rightIndex = sourceCount - targetCount; + if (fromIndex < 0) { + return -1; + } + if (fromIndex > rightIndex) { + fromIndex = rightIndex; + } + /* Empty string always matches. */ + if (targetCount == 0) { + return fromIndex; + } + + int strLastIndex = targetOffset + targetCount - 1; + char strLastChar = target[strLastIndex]; + int min = sourceOffset + targetCount - 1; + int i = min + fromIndex; + + startSearchForLastChar: while (true) { + while (i >= min && source[i] != strLastChar) { + i--; + } + if (i < min) { + return -1; + } + int j = i - 1; + int start = j - (targetCount - 1); + int k = strLastIndex - 1; + + while (j > start) { + if (source[j--] != target[k--]) { + i--; + continue startSearchForLastChar; + } + } + return start - sourceOffset + 1; + } + } + + @Test + public void run0() throws Throwable { + Assert.assertEquals(7, test(v1, 0, v1.length, v2, 0, v2.length, 10)); + } + + @Test + public void run1() throws Throwable { + Assert.assertEquals(-1, test(v1, 0, v1.length, v3, 0, v3.length, 10)); + } + + @Test + public void run2() throws Throwable { + Assert.assertEquals(-1, test(v1, 0, v1.length, v4, 0, v4.length, 10)); + } + + @Test + public void run3() throws Throwable { + Assert.assertEquals(-1, test(v1, 1, v1.length - 1, v3, 0, v3.length, 10)); + } + + @Test(expected = ArrayIndexOutOfBoundsException.class) + public void run4() throws Throwable { + Assert.assertEquals(-1, test(v1, 1, v1.length, v3, 0, v3.length, 10)); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,86 @@ +/* + * 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.jtt.loop; + +import org.junit.*; + +public class LoopParseLong { + + public static long test(String s, int radix) throws NumberFormatException { + if (s == null) { + throw new NumberFormatException("null"); + } + if (radix < Character.MIN_RADIX) { + throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); + } + if (radix > Character.MAX_RADIX) { + throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); + } + long result = 0; + boolean negative = false; + int i = 0; + int len = s.length(); + long limit = -Long.MAX_VALUE; + long multmin; + int digit; + if (len > 0) { + char firstChar = s.charAt(0); + if (firstChar < '0') { + if (firstChar == '-') { + negative = true; + limit = Long.MIN_VALUE; + } else if (firstChar != '+') { + throw new NumberFormatException(); + } + if (len == 1) { + throw new NumberFormatException(); + } + i++; + } + multmin = limit / radix; + while (i < len) { + digit = Character.digit(s.charAt(i++), radix); + if (digit < 0) { + throw new NumberFormatException(); + } + if (result < multmin) { + throw new NumberFormatException(); + } + result *= radix; + if (result < limit + digit) { + throw new NumberFormatException(); + } + result -= digit; + } + } else { + throw new NumberFormatException(); + } + return negative ? result : -result; + } + + @Test + public void run0() throws Throwable { + Assert.assertEquals(Character.digit('7', 10), test("7", 10)); + Assert.assertEquals(-100, test("-100", 10)); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Fri Apr 20 13:44:06 2012 +0200 @@ -510,7 +510,7 @@ masm.bind(slowPath.continuation); } - private static class ConvertSlowPath extends AMD64SlowPath { + private static class ConvertSlowPath extends AMD64Code { public final Label start = new Label(); public final Label continuation = new Label(); private final CiValue result; diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Code.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Code.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,39 @@ +/* + * 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.lir.amd64; + +import com.oracle.max.asm.target.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +/** + * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. + */ +public abstract class AMD64Code implements LIR.Code { + @Override + public final void emitCode(TargetMethodAssembler tasm) { + emitCode(tasm, (AMD64MacroAssembler) tasm.asm); + } + + public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm); +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Fri Apr 20 13:44:06 2012 +0200 @@ -46,6 +46,9 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + if (tasm.frameContext != null) { + tasm.frameContext.leave(tasm); + } masm.ret(0); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SlowPath.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SlowPath.java Fri Apr 13 15:52:25 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +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.lir.amd64; - -import com.oracle.max.asm.target.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -/** - * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. - */ -public abstract class AMD64SlowPath implements LIR.SlowPath { - @Override - public final void emitCode(TargetMethodAssembler tasm) { - emitCode(tasm, (AMD64MacroAssembler) tasm.asm); - } - - public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm); -} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Fri Apr 20 13:44:06 2012 +0200 @@ -85,6 +85,12 @@ public final RiRegisterConfig registerConfig; /** + * The initial frame size, not including the size of the return address. + * This is the constant space reserved by the runtime for all compiled methods. + */ + public final int initialFrameSize; + + /** * The final frame size, not including the size of the return address. * The value is only set after register allocation is complete, i.e., after all spill slots have been allocated. */ @@ -112,6 +118,11 @@ private final CiStackSlot customArea; /** + * Records whether an offset to an incoming stack argument was ever returned by {@link #offsetForStackSlot(CiStackSlot)}. + */ + private boolean accessesCallerFrame; + + /** * Creates a new frame map for the specified method. */ public FrameMap(RiRuntime runtime, CiTarget target, RiRegisterConfig registerConfig) { @@ -123,9 +134,9 @@ this.outgoingSize = runtime.getMinimumOutgoingSize(); this.objectStackBlocks = new ArrayList<>(); this.customArea = allocateStackBlock(runtime.getCustomStackAreaSize(), false); + this.initialFrameSize = currentFrameSize(); } - private int returnAddressSize() { return target.arch.returnAddressSize; } @@ -136,6 +147,13 @@ } /** + * Determines if an offset to an incoming stack argument was ever returned by {@link #offsetForStackSlot(CiStackSlot)}. + */ + public boolean accessesCallerFrame() { + return accessesCallerFrame; + } + + /** * Gets the frame size of the compiled frame, not including the size of the return address. * @return The size of the frame (in bytes). */ @@ -153,20 +171,20 @@ } /** - * Sets the frame size for this frame. - * @param frameSize The frame size (in bytes). + * Gets the current size of this frame. This is the size that would be returned by + * {@link #frameSize()} if {@link #finish()} were called now. */ - public void setFrameSize(int frameSize) { - assert this.frameSize == -1 : "must only be set once"; - this.frameSize = frameSize; + public int currentFrameSize() { + return target.alignFrameSize(outgoingSize + spillSize - returnAddressSize()); } /** - * Computes the frame size for this frame. After this method has been called, methods that change the + * Computes the final size of this frame. After this method has been called, methods that change the * frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can be requested. */ public void finish() { - setFrameSize(target.alignFrameSize(outgoingSize + spillSize - returnAddressSize())); + assert this.frameSize == -1 : "must only be set once"; + frameSize = currentFrameSize(); } /** @@ -180,6 +198,9 @@ assert (!slot.rawAddFrameSize() && slot.rawOffset() < outgoingSize) || (slot.rawAddFrameSize() && slot.rawOffset() < 0 && -slot.rawOffset() <= spillSize) || (slot.rawAddFrameSize() && slot.rawOffset() >= 0); + if (slot.inCallerFrame()) { + accessesCallerFrame = true; + } return slot.offset(totalFrameSize()); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Fri Apr 20 13:44:06 2012 +0200 @@ -42,7 +42,7 @@ * The nodes for the blocks. * TODO: This should go away, we want all nodes connected with a next-pointer. */ - private final BlockMap> nodesFor; + private final BlockMap> blockToNodesMap; /** * The linear-scan ordered list of blocks. @@ -54,15 +54,9 @@ */ private final List codeEmittingOrder; - - public final List slowPaths; - - public final List deoptimizationStubs; + public final List slowPaths; - /** - * The last slow path emitted, which can be used emit marker bytes. - */ - public SlowPath methodEndMarker; + public final List deoptimizationStubs; private int numVariables; @@ -73,7 +67,12 @@ LIRInstruction createExchange(CiValue input1, CiValue input2); } - public interface SlowPath { + private boolean hasArgInCallerFrame; + + /** + * An opaque chunk of machine code. + */ + public interface Code { void emitCode(TargetMethodAssembler tasm); } @@ -82,9 +81,9 @@ * @param numLoops number of loops * @param compilation the compilation */ - public LIR(ControlFlowGraph cfg, BlockMap> nodesFor, List linearScanOrder, List codeEmittingOrder) { + public LIR(ControlFlowGraph cfg, BlockMap> blockToNodesMap, List linearScanOrder, List codeEmittingOrder) { this.cfg = cfg; - this.nodesFor = nodesFor; + this.blockToNodesMap = blockToNodesMap; this.codeEmittingOrder = codeEmittingOrder; this.linearScanOrder = linearScanOrder; @@ -92,8 +91,25 @@ deoptimizationStubs = new ArrayList<>(); } + /** + * Gets the nodes in a given block. + */ public List nodesFor(Block block) { - return nodesFor.get(block); + return blockToNodesMap.get(block); + } + + /** + * Determines if any instruction in the LIR has any debug info associated with it. + */ + public boolean hasDebugInfo() { + for (Block b : linearScanOrder()) { + for (LIRInstruction op : b.lir) { + if (op.info != null) { + return true; + } + } + } + return false; } /** @@ -117,20 +133,25 @@ } public void emitCode(TargetMethodAssembler tasm) { + if (tasm.frameContext != null) { + tasm.frameContext.enter(tasm); + } + for (Block b : codeEmittingOrder()) { emitBlock(tasm, b); } // generate code for slow cases - for (SlowPath sp : slowPaths) { + for (Code sp : slowPaths) { + emitSlowPath(tasm, sp); + } + for (Code sp : tasm.slowPaths) { emitSlowPath(tasm, sp); } // generate deoptimization stubs - for (SlowPath sp : deoptimizationStubs) { + for (Code sp : deoptimizationStubs) { emitSlowPath(tasm, sp); } - // generate traps at the end of the method - emitSlowPath(tasm, methodEndMarker); } private static void emitBlock(TargetMethodAssembler tasm, Block block) { @@ -161,13 +182,25 @@ } } - private static void emitSlowPath(TargetMethodAssembler tasm, SlowPath sp) { + private static void emitSlowPath(TargetMethodAssembler tasm, Code sp) { if (Debug.isDumpEnabled()) { tasm.blockComment(String.format("slow case %s", sp.getClass().getName())); } sp.emitCode(tasm); } + public void setHasArgInCallerFrame() { + hasArgInCallerFrame = true; + } + + /** + * Determines if any of the parameters to the method are passed via the stack + * where the parameters are located in the caller's frame. + */ + public boolean hasArgInCallerFrame() { + return hasArgInCallerFrame; + } + /* private int lastDecodeStart; diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/FrameContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/FrameContext.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,49 @@ +/* + * 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.lir.asm; + + +/** + * Code for managing a method's native frame. + */ +public interface FrameContext { + /** + * Emits code common to all entry points of a method. This may include: + *
    + *
  • setting up the stack frame
  • + *
  • saving callee-saved registers
  • + *
  • stack overflow checking
  • + *
+ */ + void enter(TargetMethodAssembler tasm); + + /** + * Emits code to be executed just prior to returning from a method. This may include: + *
    + *
  • restoring callee-saved registers
  • + *
  • performing a safepoint
  • + *
  • destroying the stack frame
  • + *
+ */ + void leave(TargetMethodAssembler tasm); +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Fri Apr 20 13:44:06 2012 +0200 @@ -51,18 +51,25 @@ public final CiTarget target; public final RiRuntime runtime; public final FrameMap frameMap; - public final List slowPaths; + public final List slowPaths; + + /** + * The object that emits code for managing a method's frame. + * If null, no frame is used by the method. + */ + public final FrameContext frameContext; private List exceptionInfoList; private int lastSafepointPos; - public TargetMethodAssembler(CiTarget target, RiRuntime runtime, FrameMap frameMap, List slowPaths, AbstractAssembler asm) { + public TargetMethodAssembler(CiTarget target, RiRuntime runtime, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext) { this.target = target; this.runtime = runtime; this.frameMap = frameMap; - this.slowPaths = slowPaths; + this.slowPaths = new ArrayList<>(); this.asm = asm; this.targetMethod = new CiTargetMethod(); + this.frameContext = frameContext; // 0 is a valid pc for safepoints in template methods this.lastSafepointPos = -1; } @@ -71,6 +78,10 @@ targetMethod.setFrameSize(frameSize); } + public CiTargetMethod.Mark recordMark(Object id) { + return targetMethod.recordMark(asm.codeBuffer.position(), id, null); + } + public CiTargetMethod.Mark recordMark(Object id, CiTargetMethod.Mark[] references) { return targetMethod.recordMark(asm.codeBuffer.position(), id, references); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java Fri Apr 20 13:44:06 2012 +0200 @@ -46,7 +46,7 @@ assert dominated.getDominator() == block; } - assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block; + assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block : block.beginNode; } if (cfg.getLoops() != null) { @@ -58,8 +58,16 @@ Loop blockLoop = block.getLoop(); while (blockLoop != loop) { + assert blockLoop != null; blockLoop = blockLoop.parent; - assert blockLoop != null; + } + + if (!(block.isLoopHeader() && block.getLoop() == loop)) { + for (Block pred : block.getPredecessors()) { + if (!loop.blocks.contains(pred)) { + return false; + } + } } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Fri Apr 20 13:44:06 2012 +0200 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -201,26 +202,51 @@ Loop loop = new Loop(block.getLoop(), loopsList.size(), block); loopsList.add(loop); - for (LoopEndNode end : ((LoopBeginNode) beginNode).loopEnds()) { + LoopBeginNode loopBegin = (LoopBeginNode) beginNode; + for (LoopEndNode end : loopBegin.loopEnds()) { Block endBlock = nodeToBlock.get(end); computeLoopBlocks(endBlock, loop); } + + for (LoopExitNode exit : loopBegin.loopExits()) { + Block exitBlock = nodeToBlock.get(exit); + List predecessors = exitBlock.getPredecessors(); + assert predecessors.size() == 1; + computeLoopBlocks(predecessors.get(0), loop); + loop.exits.add(exitBlock); + } + List unexpected = new LinkedList<>(); + for (Block b : loop.blocks) { + for (Block sux : b.getSuccessors()) { + if (sux.loop != loop) { + BeginNode begin = sux.getBeginNode(); + if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) { + Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux); + unexpected.add(sux); + } + } + } + } + for (Block b : unexpected) { + addBranchToLoop(loop, b); + } } } loops = loopsList.toArray(new Loop[loopsList.size()]); + } - for (Loop loop : loops) { - for (Block block : loop.blocks) { - for (Block sux : block.getSuccessors()) { - if (sux.getLoopDepth() < loop.depth) { - loop.exits.add(sux); - } - } - } + private static void addBranchToLoop(Loop l, Block b) { + if (l.blocks.contains(b)) { + return; + } + l.blocks.add(b); + b.loop = l; + for (Block sux : b.getSuccessors()) { + addBranchToLoop(l, sux); } } - private void computeLoopBlocks(Block block, Loop loop) { + private static void computeLoopBlocks(Block block, Loop loop) { if (block.getLoop() == loop) { return; } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Loop.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Loop.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Loop.java Fri Apr 20 13:44:06 2012 +0200 @@ -24,6 +24,8 @@ import java.util.*; +import com.oracle.graal.nodes.*; + public class Loop { public final Loop parent; public final List children; @@ -53,4 +55,8 @@ public String toString() { return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : ""); } + + public LoopBeginNode loopBegin() { + return (LoopBeginNode) header.getBeginNode(); + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java Fri Apr 20 13:44:06 2012 +0200 @@ -24,10 +24,10 @@ import java.util.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; /** * Graal-specific extensions for the runtime interface that must be implemented by the VM. diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +import static com.oracle.graal.graph.iterators.NodePredicates.*; + import java.util.*; import com.oracle.graal.graph.*; @@ -59,28 +61,45 @@ // This begin node is necessary. } else { // This begin node can be removed and all guards moved up to the preceding begin node. - if (!usages().isEmpty()) { - Node prevBegin = prev; - while (!(prevBegin instanceof BeginNode)) { - prevBegin = prevBegin.predecessor(); - } - for (Node usage : usages()) { - tool.addToWorkList(usage); - } - replaceAtUsages(prevBegin); - } + prepareDelete(); ((StructuredGraph) graph()).removeFixed(this); } } - public void evacuateGuards() { + public static BeginNode prevBegin(FixedNode from) { + Node prevBegin = from; + while (prevBegin != null) { + if (prevBegin instanceof BeginNode) { + return (BeginNode) prevBegin; + } + prevBegin = prevBegin.predecessor(); + } + return null; + } + + public void evacuateGuards(FixedNode evacuateFrom) { if (!usages().isEmpty()) { - Node prevBegin = predecessor(); + BeginNode prevBegin = prevBegin(evacuateFrom); assert prevBegin != null; - while (!(prevBegin instanceof BeginNode)) { - prevBegin = prevBegin.predecessor(); + for (Node anchored : anchored().snapshot()) { + anchored.replaceFirstInput(this, prevBegin); } - replaceAtUsages(prevBegin); + } + } + + public void prepareDelete() { + prepareDelete((FixedNode) predecessor()); + } + + public void prepareDelete(FixedNode evacuateFrom) { + removeProxies(); + evacuateGuards(evacuateFrom); + } + + public void removeProxies() { + StructuredGraph graph = (StructuredGraph) graph(); + for (ValueProxyNode vpn : proxies().snapshot()) { + graph.replaceFloating(vpn, vpn.value()); } } @@ -98,4 +117,53 @@ public NodeIterable guards() { return usages().filter(GuardNode.class); } + + public NodeIterable anchored() { + return usages().filter(isNotA(ValueProxyNode.class)); + } + + public NodeIterable proxies() { + return usages().filter(ValueProxyNode.class); + } + + public NodeIterable getBlockNodes() { + return new NodeIterable() { + @Override + public Iterator iterator() { + return new BlockNodeIterator(BeginNode.this); + } + }; + } + + private class BlockNodeIterator implements Iterator { + private FixedNode current; + + public BlockNodeIterator(FixedNode next) { + this.current = next; + } + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public FixedNode next() { + FixedNode ret = current; + if (ret == null) { + throw new NoSuchElementException(); + } + if (!(current instanceof FixedWithNextNode) || (current instanceof BeginNode && current != BeginNode.this)) { + current = null; + } else { + current = ((FixedWithNextNode) current).next(); + } + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -53,4 +53,9 @@ return properties; } + @Override + public boolean verify() { + assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float"); + return super.verify(); + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Fri Apr 20 13:44:06 2012 +0200 @@ -161,7 +161,7 @@ } public void addVirtualObjectMapping(Node virtualObject) { - assert virtualObject instanceof VirtualObjectFieldNode || virtualObject instanceof PhiNode : virtualObject; + assert virtualObject instanceof VirtualObjectFieldNode || virtualObject instanceof PhiNode || virtualObject instanceof ValueProxyNode : virtualObject; virtualObjectMappings.add(virtualObject); } @@ -184,6 +184,13 @@ return duplicate(newBci, false); } + /** + * Gets a copy of this frame state. + */ + public FrameState duplicate() { + return duplicate(bci); + } + public FrameState duplicate(int newBci, boolean duplicateOuter) { FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize, rethrowException, duringCall)); other.values.setAll(values); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -161,14 +161,16 @@ EndNode falseEnd = (EndNode) falseSuccessor.next(); assert trueEnd.merge() == falseEnd.merge(); + FixedWithNextNode pred = (FixedWithNextNode) predecessor(); MergeNode merge = trueEnd.merge(); + merge.prepareDelete(pred); assert merge.usages().isEmpty(); FixedNode next = merge.next(); merge.setNext(null); setTrueSuccessor(null); setFalseSuccessor(null); - ((FixedWithNextNode) predecessor()).setNext(next); + pred.setNext(next); safeDelete(); trueSuccessor.safeDelete(); falseSuccessor.safeDelete(); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +import static com.oracle.graal.graph.iterators.NodePredicates.*; + import java.util.*; import com.oracle.graal.graph.*; @@ -49,8 +51,17 @@ return usages().filter(LoopEndNode.class); } + public NodeIterable loopExits() { + return usages().filter(LoopExitNode.class); + } + + @Override + public NodeIterable anchored() { + return super.anchored().filter(isNotA(LoopEndNode.class).nor(LoopExitNode.class)); + } + public List orderedLoopEnds() { - List snapshot = usages().filter(LoopEndNode.class).snapshot(); + List snapshot = loopEnds().snapshot(); Collections.sort(snapshot, new Comparator() { @Override public int compare(LoopEndNode o1, LoopEndNode o2) { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,42 @@ +/* + * 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.nodes; + +import com.oracle.graal.nodes.spi.*; + +public class LoopExitNode extends BeginNode { + @Input(notDataflow = true) private LoopBeginNode loopBegin; + public LoopExitNode(LoopBeginNode loop) { + assert loop != null; + loopBegin = loop; + } + + public LoopBeginNode loopBegin() { + return loopBegin; + } + + @Override + public void simplify(SimplifierTool tool) { + // + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -115,34 +115,57 @@ } public NodeIterable phis() { - return this.usages().filter(new NodePredicate() { + return this.usages().filter(PhiNode.class).filter(new NodePredicate() { @Override public boolean apply(Node n) { - return n instanceof PhiNode && ((PhiNode) n).merge() == MergeNode.this; + return ((PhiNode) n).merge() == MergeNode.this; } - }).filter(PhiNode.class); + }); + } + + @Override + public NodeIterable anchored() { + return super.anchored().filter(isNotA(PhiNode.class).or(new NodePredicate() { + @Override + public boolean apply(Node n) { + return ((PhiNode) n).merge() != MergeNode.this; + } + })); } @Override public void simplify(SimplifierTool tool) { FixedNode next = next(); - if (next instanceof LoopEndNode) { - LoopEndNode origLoopEnd = (LoopEndNode) next; - LoopBeginNode begin = origLoopEnd.loopBegin(); + if (next instanceof EndNode) { + EndNode origLoopEnd = (EndNode) next; + MergeNode merge = origLoopEnd.merge(); + if (merge instanceof LoopBeginNode && !(origLoopEnd instanceof LoopEndNode)) { + return; + } + // in order to move anchored values to the other merge we would need to check if the anchors are used by phis of the other merge + if (this.anchored().isNotEmpty()) { + return; + } for (PhiNode phi : phis()) { for (Node usage : phi.usages().filter(isNotA(FrameState.class))) { - if (!begin.isPhiAtMerge(usage)) { + if (!merge.isPhiAtMerge(usage)) { return; } } } - Debug.log("Split %s into loop ends for %s", this, begin); + Debug.log("Split %s into ends for %s.", this, merge); int numEnds = this.forwardEndCount(); StructuredGraph graph = (StructuredGraph) graph(); for (int i = 0; i < numEnds - 1; i++) { EndNode end = forwardEndAt(numEnds - 1 - i); - LoopEndNode loopEnd = graph.add(new LoopEndNode(begin)); - for (PhiNode phi : begin.phis()) { + EndNode newEnd; + if (merge instanceof LoopBeginNode) { + newEnd = graph.add(new LoopEndNode((LoopBeginNode) merge)); + } else { + newEnd = graph.add(new EndNode()); + merge.addForwardEnd(newEnd); + } + for (PhiNode phi : merge.phis()) { ValueNode v = phi.valueAt(origLoopEnd); ValueNode newInput; if (isPhiAtMerge(v)) { @@ -154,9 +177,9 @@ phi.addInput(newInput); } this.removeEnd(end); - end.replaceAtPredecessors(loopEnd); + end.replaceAtPredecessors(newEnd); end.safeDelete(); - tool.addToWorkList(loopEnd.predecessor()); + tool.addToWorkList(newEnd.predecessor()); // ? } graph.reduceTrivialMerge(this); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -33,22 +33,15 @@ * and a variable. */ public final class PhiNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType { - - @Input(notDataflow = true) private MergeNode merge; - - @Input private final NodeInputList values = new NodeInputList<>(this); - - public MergeNode merge() { - return merge; - } - public static enum PhiType { Value, // normal value phis Memory, // memory phis Virtual // phis used for VirtualObjectField merges } - private final PhiType type; + @Input(notDataflow = true) private MergeNode merge; + @Input private final NodeInputList values = new NodeInputList<>(this); + @Data private final PhiType type; public PhiNode(CiKind kind, MergeNode merge, PhiType type) { super(StampFactory.forKind(kind)); @@ -60,6 +53,10 @@ return type; } + public MergeNode merge() { + return merge; + } + public NodeInputList values() { return values; } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Fri Apr 20 13:44:06 2012 +0200 @@ -168,6 +168,9 @@ public void removeFixed(FixedWithNextNode node) { assert node != null; + if (node instanceof BeginNode) { + ((BeginNode) node).prepareDelete(); + } assert node.usages().isEmpty() : node + " " + node.usages(); FixedNode next = node.next(); node.setNext(null); @@ -208,15 +211,11 @@ assert node.usages().isEmpty(); assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; BeginNode begin = node.blockSuccessor(survivingSuccessor); - begin.evacuateGuards(); - FixedNode next = begin.next(); - begin.setNext(null); for (int i = 0; i < node.blockSuccessorCount(); i++) { node.setBlockSuccessor(i, null); } - node.replaceAtPredecessors(next); + node.replaceAtPredecessors(begin); node.safeDelete(); - begin.safeDelete(); } public void removeSplitPropagate(ControlSplitNode node, int survivingSuccessor) { @@ -224,9 +223,6 @@ assert node.usages().isEmpty(); assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; BeginNode begin = node.blockSuccessor(survivingSuccessor); - begin.evacuateGuards(); - FixedNode next = begin.next(); - begin.setNext(null); for (int i = 0; i < node.blockSuccessorCount(); i++) { BeginNode successor = node.blockSuccessor(i); node.setBlockSuccessor(i, null); @@ -234,10 +230,9 @@ GraphUtil.killCFG(successor); } } - if (next.isAlive()) { - node.replaceAtPredecessors(next); + if (begin.isAlive()) { + node.replaceAtPredecessors(begin); node.safeDelete(); - begin.safeDelete(); } else { assert node.isDeleted(); } @@ -257,31 +252,23 @@ assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; BeginNode begin = node.blockSuccessor(survivingSuccessor); - begin.evacuateGuards(); - FixedNode next = begin.next(); - begin.setNext(null); for (int i = 0; i < node.blockSuccessorCount(); i++) { node.setBlockSuccessor(i, null); } - replacement.setNext(next); + replacement.setNext(begin); node.replaceAndDelete(replacement); - begin.safeDelete(); } public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, int survivingSuccessor) { assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; BeginNode begin = node.blockSuccessor(survivingSuccessor); - begin.evacuateGuards(); - FixedNode next = begin.next(); - begin.setNext(null); for (int i = 0; i < node.blockSuccessorCount(); i++) { node.setBlockSuccessor(i, null); } - node.replaceAtPredecessors(next); + node.replaceAtPredecessors(begin); node.replaceAtUsages(replacement); node.safeDelete(); - begin.safeDelete(); } public void addAfterFixed(FixedWithNextNode node, FixedWithNextNode newNode) { @@ -325,14 +312,15 @@ EndNode singleEnd = merge.forwardEndAt(0); FixedNode sux = merge.next(); FrameState stateAfter = merge.stateAfter(); + // remove loop exits + if (merge instanceof LoopBeginNode) { + for (LoopExitNode exit : ((LoopBeginNode) merge).loopExits().snapshot()) { + exit.removeProxies(); + replaceFixedWithFixed(exit, this.add(new BeginNode())); + } + } // evacuateGuards - Node prevBegin = singleEnd.predecessor(); - assert prevBegin != null; - while (!(prevBegin instanceof BeginNode)) { - prevBegin = prevBegin.predecessor(); - } - merge.replaceAtUsages(prevBegin); - + merge.prepareDelete((FixedNode) singleEnd.predecessor()); merge.safeDelete(); if (stateAfter != null && stateAfter.usages().isEmpty()) { stateAfter.safeDelete(); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -0,0 +1,63 @@ +/* + * 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.nodes; + +import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.Node.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.calc.*; + + + +public class ValueProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable { + @Input(notDataflow = true) private BeginNode proxyPoint; + @Input private ValueNode value; + @Data private final PhiType type; + + public ValueProxyNode(ValueNode value, BeginNode exit, PhiType type) { + super(value.stamp()); + this.type = type; + assert exit != null; + this.proxyPoint = exit; + this.value = value; + } + + public ValueNode value() { + return value; + } + + public BeginNode proxyPoint() { + return proxyPoint; + } + + public PhiType type() { + return type; + } + + @Override + public boolean verify() { + assert value != null; + assert proxyPoint != null; + return super.verify(); + } +} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -52,7 +52,7 @@ return x(); } if (c == 0) { - return ConstantNode.forInt(0, graph()); + return ConstantNode.defaultForKind(kind(), graph()); } if (c > 0 && CiUtil.isPowerOf2(c)) { return graph().unique(new LeftShiftNode(kind(), x(), ConstantNode.forInt(CiUtil.log2(c), graph()))); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -50,10 +50,6 @@ return offset; } - public UnsafeLoadNode(ValueNode object, ValueNode offset, CiKind kind) { - this(object, 0, offset, kind); - } - public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, CiKind kind) { super(StampFactory.forKind(kind.stackKind())); this.object = object; @@ -73,7 +69,7 @@ @SuppressWarnings("unused") @NodeIntrinsic - public static T load(Object object, long offset, @ConstantNodeParameter CiKind kind) { + public static T load(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -22,11 +22,11 @@ */ package com.oracle.graal.nodes.extended; -import com.oracle.max.cri.ci.*; import com.oracle.graal.cri.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ci.*; /** * Store of a value at a location specified as an offset relative to an object. @@ -39,10 +39,6 @@ @Data private final int displacement; @Data private final CiKind storeKind; - public UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, CiKind kind) { - this(object, 0, offset, value, kind); - } - public UnsafeStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value, CiKind kind) { super(StampFactory.illegal()); assert kind != CiKind.Void && kind != CiKind.Illegal; @@ -81,55 +77,56 @@ // specialized on value type until boxing/unboxing is sorted out in intrinsification @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, Object value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, Object value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, boolean value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, boolean value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, byte value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, byte value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, char value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, char value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, double value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, double value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, float value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, float value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, int value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, int value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, long value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, long value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static void store(Object object, long offset, short value, @ConstantNodeParameter CiKind kind) { + public static void store(Object object, @ConstantNodeParameter int displacement, long offset, short value, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException(); } + } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -36,6 +36,8 @@ @Input private ValueNode index; @Input private ValueNode length; + @Data private final CiKind elementType; + private final long leafGraphId; public ValueNode index() { return index; @@ -45,9 +47,6 @@ return length; } - private final CiKind elementType; - private final long leafGraphId; - /** * Create an new AccessIndexedNode. * @param kind the result kind of the access diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -39,7 +39,7 @@ */ public final class CheckCastNode extends TypeCheckNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable { - @Input protected final FixedNode anchor; + @Input(notDataflow = true) protected final FixedNode anchor; @Data protected final boolean emitCode; public FixedNode anchor() { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -22,12 +22,12 @@ */ package com.oracle.graal.nodes.java; -import com.oracle.max.cri.ci.*; import com.oracle.graal.cri.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ci.*; /** * Represents an atomic compare-and-swap operation @@ -39,6 +39,7 @@ @Input private ValueNode offset; @Input private ValueNode expected; @Input private ValueNode newValue; + @Data private final int displacement; public ValueNode object() { return object; @@ -56,13 +57,18 @@ return newValue; } - public CompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue) { + public int displacement() { + return displacement; + } + + public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue) { super(StampFactory.forKind(CiKind.Boolean.stackKind())); assert expected.kind() == newValue.kind(); this.object = object; this.offset = offset; this.expected = expected; this.newValue = newValue; + this.displacement = displacement; } @Override @@ -78,19 +84,19 @@ // specialized on value type until boxing/unboxing is sorted out in intrinsification @SuppressWarnings("unused") @NodeIntrinsic - public static boolean compareAndSwap(Object object, long offset, Object expected, Object newValue) { + public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, Object expected, Object newValue) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static boolean compareAndSwap(Object object, long offset, long expected, long newValue) { + public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, long expected, long newValue) { throw new UnsupportedOperationException(); } @SuppressWarnings("unused") @NodeIntrinsic - public static boolean compareAndSwap(Object object, long offset, int expected, int newValue) { + public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, int expected, int newValue) { throw new UnsupportedOperationException(); } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -22,16 +22,16 @@ */ package com.oracle.graal.nodes.java; -import com.oracle.max.cri.ci.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ci.*; /** * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler. */ -public final class ExceptionObjectNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint { +public class ExceptionObjectNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint { /** * Constructs a new ExceptionObject instruction. @@ -44,4 +44,10 @@ public void generate(LIRGeneratorTool gen) { gen.visitExceptionObject(this); } + + @Override + public boolean verify() { + assertTrue(stateAfter() != null, "an exception handler needs a frame state"); + return super.verify(); + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.types.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; /** * The {@code NewArrayNode} class is the base of all instructions that allocate arrays. @@ -130,7 +131,7 @@ public int updateState(Node node, Node current, Map fieldIndex, ValueNode[] fieldState) { if (current instanceof AccessIndexedNode) { AccessIndexedNode x = (AccessIndexedNode) current; - if (x.array() == node) { + if (GraphUtil.unProxify(x.array()) == node) { int index = ((AccessIndexedNode) current).index().asConstant().asInt(); if (current instanceof LoadIndexedNode) { x.replaceAtUsages(fieldState[index]); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; /** * The {@code NewInstanceNode} represents the allocation of an instance class object. @@ -110,7 +111,7 @@ public int updateState(Node node, Node current, Map fieldIndex, ValueNode[] fieldState) { if (current instanceof AccessFieldNode) { AccessFieldNode x = (AccessFieldNode) current; - if (x.object() == node) { + if (GraphUtil.unProxify(x.object()) == node) { int field = fieldIndex.get(x.field()); StructuredGraph graph = (StructuredGraph) x.graph(); if (current instanceof LoadFieldNode) { diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Fri Apr 20 13:44:06 2012 +0200 @@ -81,6 +81,13 @@ } else if (usage instanceof ArrayLengthNode) { assert ((ArrayLengthNode) usage).array() == node; return false; + } else if (usage instanceof ValueProxyNode) { + for (Node vpnUsage : usage.usages().snapshot()) { + if (escape(usage, vpnUsage)) { + return true; + } + } + return false; } else { return true; } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Fri Apr 20 13:44:06 2012 +0200 @@ -98,14 +98,11 @@ public abstract void visitEndNode(EndNode i); public abstract void visitLoopEnd(LoopEndNode i); - // The CompareAndSwapNode in its current form needs to be lowered to several Nodes before code generation to separate three parts: - // * The write barriers (and possibly read barriers) when accessing an object field - // * The distinction of returning a boolean value (semantic similar to a BooleanNode to be used as a condition?) or the old value being read - // * The actual compare-and-swap public abstract void visitCompareAndSwap(CompareAndSwapNode i); // Functionality that is currently implemented in XIR. - // These methods will go away eventually when lowering is done via snippets in the front end. + // Some of these methods will go away when lowering is done via snippets in the front end. + // The remainder will define the contract a runtime specific backend must provide. public abstract void visitCheckCast(CheckCastNode i); public abstract void visitMonitorEnter(MonitorEnterNode i); public abstract void visitMonitorExit(MonitorExitNode i); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Fri Apr 20 13:44:06 2012 +0200 @@ -27,8 +27,10 @@ import java.util.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.virtual.*; public class GraphUtil { @@ -40,7 +42,11 @@ killEnd(end); } else { // Normal control flow node. - for (Node successor : node.successors().snapshot()) { + /* We do not take a successor snapshot because this iterator supports concurrent modifications + * as long as they do not change the size of the successor list. Not tasking a snapshot allows + * us to see modifications to other branches that may happen while processing one branch. + */ + for (Node successor : node.successors()) { killCFG((FixedNode) successor); } } @@ -50,28 +56,39 @@ private static void killEnd(EndNode end) { MergeNode merge = end.merge(); merge.removeEnd(end); + StructuredGraph graph = (StructuredGraph) end.graph(); if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop for (PhiNode phi : merge.phis().snapshot()) { propagateKill(phi); } LoopBeginNode begin = (LoopBeginNode) merge; - // disconnect and delete loop ends + // disconnect and delete loop ends & loop exits for (LoopEndNode loopend : begin.loopEnds().snapshot()) { loopend.predecessor().replaceFirstSuccessor(loopend, null); loopend.safeDelete(); } + for (LoopExitNode loopexit : begin.loopExits().snapshot()) { + for (ValueProxyNode vpn : loopexit.proxies().snapshot()) { + graph.replaceFloating(vpn, vpn.value()); + } + graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode())); + } killCFG(begin.next()); begin.safeDelete(); } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore - ((StructuredGraph) end.graph()).reduceDegenerateLoopBegin((LoopBeginNode) merge); + graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore - ((StructuredGraph) end.graph()).reduceTrivialMerge(merge); + graph.reduceTrivialMerge(merge); } } + public static NodePredicate isFloatingNode() { + return isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class).or(VirtualObjectFieldNode.class).or(VirtualObjectNode.class); + } + public static void propagateKill(Node node) { if (node != null && node.isAlive()) { - List usagesSnapshot = node.usages().filter(isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class)).snapshot(); + List usagesSnapshot = node.usages().filter(isFloatingNode()).snapshot(); // null out remaining usages node.replaceAtUsages(null); @@ -91,7 +108,7 @@ } public static void killUnusedFloatingInputs(Node node) { - List floatingInputs = node.inputs().filter(isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class)).snapshot(); + List floatingInputs = node.inputs().filter(isFloatingNode()).snapshot(); node.safeDelete(); for (Node in : floatingInputs) { @@ -100,4 +117,70 @@ } } } + + public static void checkRedundantPhi(PhiNode phiNode) { + if (phiNode.isDeleted() || phiNode.valueCount() == 1) { + return; + } + + ValueNode singleValue = phiNode.singleValue(); + if (singleValue != null) { + Collection phiUsages = phiNode.usages().filter(PhiNode.class).snapshot(); + Collection proxyUsages = phiNode.usages().filter(ValueProxyNode.class).snapshot(); + ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue); + for (PhiNode phi : phiUsages) { + checkRedundantPhi(phi); + } + for (ValueProxyNode proxy : proxyUsages) { + checkRedundantProxy(proxy); + } + } + } + + public static void checkRedundantProxy(ValueProxyNode vpn) { + BeginNode proxyPoint = vpn.proxyPoint(); + if (proxyPoint instanceof LoopExitNode) { + LoopExitNode exit = (LoopExitNode) proxyPoint; + LoopBeginNode loopBegin = exit.loopBegin(); + ValueNode vpnValue = vpn.value(); + for (ValueNode v : loopBegin.stateAfter().values()) { + ValueNode v2 = v; + if (loopBegin.isPhiAtMerge(v2)) { + v2 = ((PhiNode) v2).valueAt(loopBegin.forwardEnd()); + } + if (vpnValue == v2) { + Collection phiUsages = vpn.usages().filter(PhiNode.class).snapshot(); + Collection proxyUsages = vpn.usages().filter(ValueProxyNode.class).snapshot(); + ((StructuredGraph) vpn.graph()).replaceFloating(vpn, vpnValue); + for (PhiNode phi : phiUsages) { + checkRedundantPhi(phi); + } + for (ValueProxyNode proxy : proxyUsages) { + checkRedundantProxy(proxy); + } + return; + } + } + } + } + + public static void normalizeLoopBegin(LoopBeginNode begin) { + // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either the same or the phi itself. + for (PhiNode phi : begin.phis().snapshot()) { + GraphUtil.checkRedundantPhi(phi); + } + for (LoopExitNode exit : begin.loopExits()) { + for (ValueProxyNode vpn : exit.proxies().snapshot()) { + GraphUtil.checkRedundantProxy(vpn); + } + } + } + + public static ValueNode unProxify(ValueNode proxy) { + ValueNode v = proxy; + while (v instanceof ValueProxyNode) { + v = ((ValueProxyNode) v).value(); + } + return v; + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java Fri Apr 20 13:44:06 2012 +0200 @@ -66,6 +66,13 @@ } @Override + public boolean verify() { + assertTrue(object != null, "No object"); + assertTrue(input != null, "No input"); + return super.verify(); + } + + @Override public Map getDebugProperties() { Map properties = super.getDebugProperties(); properties.put("index", index); @@ -74,7 +81,7 @@ @Override public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name && object().fields() != null) { + if (verbosity == Verbosity.Name && object() != null && object().fields() != null) { return super.toString(Verbosity.Name) + " " + object().fields()[index].name(); } else { return super.toString(verbosity); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Fri Apr 20 13:44:06 2012 +0200 @@ -109,7 +109,7 @@ cfgPrinter.printCFG(message, Arrays.asList(cfgPrinter.cfg.getBlocks())); } else if (object instanceof CiTargetMethod) { - cfgPrinter.printMachineCode(runtime.disassemble((CiTargetMethod) object), null); + cfgPrinter.printMachineCode(runtime.disassemble((CiTargetMethod) object), message); } else if (object instanceof Interval[]) { cfgPrinter.printIntervals(message, (Interval[]) object); diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSnippets.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSnippets.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSnippets.java Fri Apr 20 13:44:06 2012 +0200 @@ -35,19 +35,19 @@ private static Node getNode(Node node, long offset) { - return UnsafeCastNode.cast(UnsafeLoadNode.load(node, offset, CiKind.Object), Node.class); + return UnsafeCastNode.cast(UnsafeLoadNode.load(node, 0, offset, CiKind.Object), Node.class); } private static NodeList getNodeList(Node node, long offset) { - return UnsafeCastNode.cast(UnsafeLoadNode.load(node, offset, CiKind.Object), NodeList.class); + return UnsafeCastNode.cast(UnsafeLoadNode.load(node, 0, offset, CiKind.Object), NodeList.class); } private static void putNode(Node node, long offset, Node value) { - UnsafeStoreNode.store(node, offset, value, CiKind.Object); + UnsafeStoreNode.store(node, 0, offset, value, CiKind.Object); } private static void putNodeList(Node node, long offset, NodeList value) { - UnsafeStoreNode.store(node, offset, value, CiKind.Object); + UnsafeStoreNode.store(node, 0, offset, value, CiKind.Object); } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ArrayHeaderSizeNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ArrayHeaderSizeNode.java Fri Apr 13 15:52:25 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +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.snippets.nodes; - -import com.oracle.max.cri.ci.*; -import com.oracle.graal.cri.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class ArrayHeaderSizeNode extends FloatingNode implements Lowerable { - @Data private final CiKind elementKind; - - public ArrayHeaderSizeNode(CiKind elementKind) { - super(StampFactory.forKind(CiKind.Long)); - this.elementKind = elementKind; - } - - @Override - public void lower(CiLoweringTool tool) { - tool.getRuntime().lower(this, tool); - } - - public CiKind elementKind() { - return elementKind; - } - - @SuppressWarnings("unused") - @NodeIntrinsic - public static long sizeFor(@ConstantNodeParameter CiKind kind) { - throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); - } -} diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Fri Apr 20 13:44:06 2012 +0200 @@ -46,6 +46,11 @@ return arg1 + " " + arg2 + " " + arg3; } + Object f1; + public Object testMethodVirtual(Object arg1, Object arg2, Object arg3) { + return f1 + " " + arg1 + " " + arg2 + " " + arg3; + } + @Test public void test1() { Method method = getMethod("testMethod"); @@ -71,7 +76,37 @@ } catch (MethodInvalidatedException t) { Assert.fail("method invalidated"); } + } + @Test + public void test3() { + Method method = getMethod("testMethod"); + final StructuredGraph graph = parse(method); + final RiResolvedMethod riMethod = runtime.getRiMethod(method); + CiTargetMethod targetMethod = runtime.compile(riMethod, graph); + RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod); + try { + Object result = compiledMethod.executeVarargs("1", "2", "3"); + Assert.assertEquals("1 2 3", result); + } catch (MethodInvalidatedException t) { + Assert.fail("method invalidated"); + } + } + + @Test + public void test4() { + Method method = getMethod("testMethodVirtual"); + final StructuredGraph graph = parse(method); + final RiResolvedMethod riMethod = runtime.getRiMethod(method); + CiTargetMethod targetMethod = runtime.compile(riMethod, graph); + RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod); + try { + f1 = "0"; + Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); + Assert.assertEquals("0 1 2 3", result); + } catch (MethodInvalidatedException t) { + Assert.fail("method invalidated"); + } } @Test diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java Fri Apr 20 13:44:06 2012 +0200 @@ -226,7 +226,7 @@ System.out.print(succ + " "); } System.out.println(); - for (Node node : schedule.getNodesFor().get(block)) { + for (Node node : schedule.getBlockToNodesMap().get(block)) { System.out.println(" " + node + " (" + node.usages().size() + ")"); } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java --- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java Fri Apr 20 13:44:06 2012 +0200 @@ -54,6 +54,14 @@ protected abstract void patchJumpTarget(int branch, int jumpTarget); + /** + * Emits instruction(s) that access an address specified by a given displacement from the stack pointer + * in the direction that the stack grows (which is down on most architectures). + * + * @param disp the displacement from the stack pointer at which the stack should be accessed + */ + public abstract void bangStack(int disp); + protected final void emitByte(int x) { codeBuffer.emitByte(x); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java --- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java Fri Apr 20 13:44:06 2012 +0200 @@ -2985,4 +2985,9 @@ public void fstp(int i) { emitx87(0xDD, 0xD8, i); } + + @Override + public void bangStack(int disp) { + movq(new CiAddress(target.wordKind, AMD64.RSP, -disp), AMD64.rax); + } } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiUtil.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiUtil.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiUtil.java Fri Apr 20 13:44:06 2012 +0200 @@ -410,14 +410,6 @@ } /** - * Gets a stack trace element for a given method and bytecode index. - */ - public static StackTraceElement toStackTraceElement(RiMethod method, @SuppressWarnings("unused") int bci) { - // TODO (thomaswue): Look if we can use bci to get the line number. - return new StackTraceElement(CiUtil.toJavaName(method.holder()), method.name(), null, -1); - } - - /** * Converts a Java source-language class name into the internal form. * * @param className the class name diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiCompiledMethod.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiCompiledMethod.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiCompiledMethod.java Fri Apr 20 13:44:06 2012 +0200 @@ -44,4 +44,6 @@ boolean isValid(); Object execute(Object arg1, Object arg2, Object arg3); + + Object executeVarargs(Object... args); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java Fri Apr 20 13:44:06 2012 +0200 @@ -553,26 +553,6 @@ */ Safepoint, /** - * Align the code following this instruction to a multiple of (int)extra. - */ - Align, - /** - * Creates the stack banging overflow check. - */ - StackOverflowCheck, - /** - * Creates the stack frame for the method and spills callee-save registers (if any) to the {@linkplain CiRegisterSaveArea register save area}. - */ - PushFrame, - /** - * Restores all callee-save registers (if any) and removes the stack frame of the method. - */ - PopFrame, - /** - * Inserts an array of bytes directly into the code output. - */ - RawBytes, - /** * Pushes a value onto the stack. */ Push, @@ -769,27 +749,6 @@ append(new XirInstruction(CiKind.Void, null, Safepoint, null)); } - public void align(int multiple) { - assert multiple > 0; - append(new XirInstruction(CiKind.Void, multiple, Align, null)); - } - - public void stackOverflowCheck() { - append(new XirInstruction(CiKind.Void, null, StackOverflowCheck, null)); - } - - public void pushFrame() { - append(new XirInstruction(CiKind.Void, null, PushFrame, null)); - } - - public void popFrame() { - append(new XirInstruction(CiKind.Void, null, PopFrame, null)); - } - - public void rawBytes(byte[] bytes) { - append(new XirInstruction(CiKind.Void, bytes, RawBytes, null)); - } - public void push(XirOperand value) { append(new XirInstruction(CiKind.Void, Push, VOID, value)); } diff -r d87155082c4d -r c9dd4054c23b graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java Fri Apr 13 15:52:25 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java Fri Apr 20 13:44:06 2012 +0200 @@ -31,20 +31,6 @@ */ public interface RiXirGenerator { - /** - * Note: may return {@code null}. - */ - XirSnippet genPrologue(XirSite site, RiResolvedMethod method); - - /** - * Note: may return {@code null} in which case the compiler will not emit a return instruction. - */ - XirSnippet genEpilogue(XirSite site, RiResolvedMethod method); - - XirSnippet genSafepointPoll(XirSite site); - - XirSnippet genExceptionObject(XirSite site); - XirSnippet genInvokeInterface(XirSite site, XirArgument receiver, RiMethod method); XirSnippet genInvokeVirtual(XirSite site, XirArgument receiver, RiMethod method, boolean megamorph); diff -r d87155082c4d -r c9dd4054c23b hotspot/.project --- a/hotspot/.project Fri Apr 13 15:52:25 2012 +0200 +++ b/hotspot/.project Fri Apr 20 13:44:06 2012 +0200 @@ -23,7 +23,7 @@ org.eclipse.cdt.make.core.autoBuildTarget - product + ide-build-target org.eclipse.cdt.make.core.buildArguments @@ -86,9 +86,14 @@ - cpu + x86 2 - PARENT-1-PROJECT_LOC/src/cpu/x86 + PARENT-1-PROJECT_LOC/src/cpu/x86/vm + + + sparc + 2 + PARENT-1-PROJECT_LOC/src/cpu/sparc/vm generated @@ -101,14 +106,19 @@ WORKSPACE_LOC/make - os + linux 2 - PARENT-1-PROJECT_LOC/src/os/linux + PARENT-1-PROJECT_LOC/src/os/linux/vm - os_cpu + linux_x86 2 - PARENT-1-PROJECT_LOC/src/os_cpu/linux_x86 + PARENT-1-PROJECT_LOC/src/os_cpu/linux_x86/vm + + + linux_sparc + 2 + PARENT-1-PROJECT_LOC/src/os_cpu/linux_sparc/vm vm diff -r d87155082c4d -r c9dd4054c23b mx/commands.py --- a/mx/commands.py Fri Apr 13 15:52:25 2012 +0200 +++ b/mx/commands.py Fri Apr 20 13:44:06 2012 +0200 @@ -49,6 +49,8 @@ _jacoco = 'off' +_make_eclipse_launch = False + _jacocoExcludes = ['com.oracle.graal.hotspot.snippets.ArrayCopySnippets', 'com.oracle.graal.snippets.DoubleSnippets', 'com.oracle.graal.snippets.FloatSnippets', @@ -89,6 +91,9 @@ if opts.native: os.environ.update(ARCH_DATA_MODEL='64', LANG='C', HOTSPOT_BUILD_JOBS='16') mx.run([mx.gmake_cmd(), 'clean'], cwd=join(_graal_home, 'make')) + jdks = join(_graal_home, 'jdk' + mx.java().version) + if exists(jdks): + shutil.rmtree(jdks) def export(args): """create a GraalVM zip file for distribution""" @@ -183,7 +188,6 @@ DaCapo harness.""" numTests = {} - if len(args) > 0: level = getattr(sanitycheck.SanityCheckLevel, args[0], None) if level is not None: @@ -216,17 +220,18 @@ # The remainder are VM options vmOpts = [arg for arg in args if not arg.startswith('@')] + vm = _vm failed = [] for (test, n) in numTests.items(): - if not sanitycheck.getDacapo(test, n, dacapoArgs).test('graal', opts=vmOpts): + if not sanitycheck.getDacapo(test, n, dacapoArgs).test(vm, opts=vmOpts): failed.append(test) if len(failed) != 0: mx.abort('DaCapo failures: ' + str(failed)) def intro(args): - """"run a simple program and visualize its compilation in the Graal Visualizer""" + """run a simple program and visualize its compilation in the Graal Visualizer""" # Start the visualizer in a separate thread t = Thread(target=gv, args=([[]])) t.start() @@ -235,7 +240,7 @@ mx.log('Waiting 5 seconds for visualizer to start') time.sleep(5) - vm(['-G:Dump=HelloWorld', '-G:MethodFilter=main', '-Xcomp', '-XX:CompileOnly=HelloWorld::main', '-cp', mx.classpath('com.oracle.graal.examples')] + args + ['examples.HelloWorld']) + vm(['-G:Dump=', '-G:MethodFilter=greet', '-Xcomp', '-XX:CompileOnly=HelloWorld::greet', '-cp', mx.classpath('com.oracle.graal.examples')] + args + ['examples.HelloWorld']) def scaladacapo(args): """run one or all Scala DaCapo benchmarks @@ -278,10 +283,11 @@ # The remainder are VM options vmOpts = [arg for arg in args if not arg.startswith('@')] + vm = _vm; failed = [] for (test, n) in numTests.items(): - if not sanitycheck.getScalaDacapo(test, n, dacapoArgs).test('graal', opts=vmOpts): + if not sanitycheck.getScalaDacapo(test, n, dacapoArgs).test(vm, opts=vmOpts): failed.append(test) if len(failed) != 0: @@ -455,7 +461,30 @@ mx.abort(fp.name + ':' + str(source[:start].count('\n') + 1) + ': add missing projects to declaration:\n ' + '\n '.join(missing)) if len(extra) != 0: mx.abort(fp.name + ':' + str(source[:start].count('\n') + 1) + ': remove projects from declaration:\n ' + '\n '.join(extra)) - + + # Check if a build really needs to be done + timestampFile = join(vmDir, '.build-timestamp') + if opts2.force or not exists(timestampFile): + mustBuild = True + else: + mustBuild = False + timestamp = os.path.getmtime(timestampFile) + sources = [] + for d in ['src', 'make']: + for root, dirnames, files in os.walk(join(_graal_home, d)): + # ignore /src/share/tools + if root == join(_graal_home, 'src', 'share'): + dirnames.remove('tools') + sources += [join(root, name) for name in files] + for f in sources: + if len(f) != 0 and os.path.getmtime(f) > timestamp: + mustBuild = True + break + + if not mustBuild: + mx.log('[all files in src and make directories are older than ' + timestampFile[len(_graal_home) + 1:] + ' - skipping native build]') + continue + if platform.system() == 'Windows': compilelogfile = _graal_home + '/graalCompile.log' mksHome = mx.get_env('MKS_HOME', 'C:\\cygwin\\bin') @@ -512,7 +541,12 @@ with open(jvmCfg, 'w') as f: for line in lines: f.write(line) - + + if exists(timestampFile): + os.utime(timestampFile, None) + else: + file(timestampFile, 'a') + def vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, vmbuild=None): """run the VM selected by the '--vm' option""" @@ -520,7 +554,11 @@ vm = _vm build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product' - mx.expand_project_in_args(args) + mx.expand_project_in_args(args) + if _make_eclipse_launch: + mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True)) + if len([a for a in args if 'PrintAssembly' in a]) != 0: + hsdis([]) if mx.java().debug_port is not None: args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args if _jacoco == 'on' or _jacoco == 'append': @@ -681,6 +719,7 @@ return self parser = ArgumentParser(prog='mx gate'); + parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code') parser.add_argument('-n', '--omit-native-build', action='store_false', dest='buildNative', help='omit cleaning and building native code') parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM') parser.add_argument('--jacocout', help='specify the output directory for jacoco report') @@ -692,7 +731,12 @@ try: t = Task('Clean') - clean([] if args.buildNative else ['--no-native']) + cleanArgs = [] + if not args.buildNative: + cleanArgs.append('--no-native') + if not args.cleanJava: + cleanArgs.append('--no-java') + clean(cleanArgs) tasks.append(t.stop()) t = Task('BuildJava') @@ -732,7 +776,7 @@ for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): t = Task(str(test) + ':' + vmbuild) if not test.test('graal'): - t.abort(test.group + ' ' + test.name + ' Failed') + t.abort(test.name + ' Failed') tasks.append(t.stop()) if args.jacocout is not None: @@ -845,9 +889,10 @@ benchmarks += [sanitycheck.getSPECjvm2008([specjvm], True, 120, 120)] for test in benchmarks: - if not results.has_key(test.group): - results[test.group] = {} - results[test.group].update(test.bench(vm)) + for (group, res) in test.bench(vm).items(): + if not results.has_key(group): + results[group] = {}; + results[group].update(res) mx.log(json.dumps(results)) if resultFile: with open(resultFile, 'w') as f: @@ -882,7 +927,8 @@ mx.abort('-it (Iteration time) needs a numeric value (seconds)') vmArgs.remove('-it') benchArgs.remove(args[itIdx+1]) - sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench('graal', opts=vmArgs) + vm = _vm; + sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench(vm, opts=vmArgs) def hsdis(args): """install the hsdis library @@ -895,8 +941,19 @@ build = _vmbuild if _vmSourcesAvailable else 'product' lib = mx.lib_suffix('hsdis-amd64') path = join(_vmLibDirInJdk(_jdk(build)), lib) - mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib]) + if not exists(path): + mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib]) +def hcfdis(args): + """disassembles HexCodeFiles embedded in text files + + Run a tool over the input files to convert all embedded HexCodeFiles + to a disassembled format.""" + path = join(_graal_home, 'lib', 'hcfdis.jar') + if not exists(path): + mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hcfdis.jar']) + mx.run_java(['-jar', path] + args) + def jacocoreport(args): """creates a JaCoCo coverage report @@ -917,6 +974,7 @@ 'buildvms': [buildvms, '[-options]'], 'clean': [clean, ''], 'hsdis': [hsdis, '[att]'], + 'hcfdis': [hcfdis, ''], 'igv' : [igv, ''], 'intro': [intro, ''], 'jdkhome': [jdkhome, ''], @@ -940,6 +998,7 @@ mx.add_argument('--product', action='store_const', dest='vmbuild', const='product', help='select the product build of the VM') mx.add_argument('--debug', action='store_const', dest='vmbuild', const='debug', help='select the debug build of the VM') mx.add_argument('--fastdebug', action='store_const', dest='vmbuild', const='fastdebug', help='select the fast debug build of the VM') + mx.add_argument('--ecl', action='store_true', dest='make_eclipse_launch', help='create launch configuration for running VM execution(s) in Eclipse') commands.update({ 'export': [export, '[-options] [zipfile]'], @@ -964,5 +1023,7 @@ if hasattr(opts, 'vmbuild') and opts.vmbuild is not None: global _vmbuild _vmbuild = opts.vmbuild + global _make_eclipse_launch + _make_eclipse_launch = getattr(opts, 'make_eclipse_launch', False) global _jacoco _jacoco = opts.jacoco diff -r d87155082c4d -r c9dd4054c23b mx/projects --- a/mx/projects Fri Apr 13 15:52:25 2012 +0200 +++ b/mx/projects Fri Apr 20 13:44:06 2012 +0200 @@ -31,7 +31,7 @@ # graal.graph project@com.oracle.graal.graph@subDir=graal -project@com.oracle.graal.graph@sourceDirs=src +project@com.oracle.graal.graph@sourceDirs=src,test project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug,JUNIT project@com.oracle.graal.graph@javaCompliance=1.7 diff -r d87155082c4d -r c9dd4054c23b mx/sanitycheck.py --- a/mx/sanitycheck.py Fri Apr 13 15:52:25 2012 +0200 +++ b/mx/sanitycheck.py Fri Apr 20 13:44:06 2012 +0200 @@ -106,7 +106,7 @@ error = re.compile(r"^Errors in benchmark: ") # The ' ops/m' at the end of the success string is important : it's how you can tell valid and invalid runs apart success = re.compile(r"^(Noncompliant c|C)omposite result: [0-9]+(,|\.)[0-9]+( SPECjvm2008 (Base|Peak))? ops/m$") - matcher = Matcher(score, {'const:name' : 'benchmark', 'const:score' : 'score'}, startNewLine=True) + matcher = Matcher(score, {'const:group' : "const:SPECjvm2008", 'const:name' : 'benchmark', 'const:score' : 'score'}, startNewLine=True) opts = [] if warmupTime is not None: @@ -116,7 +116,7 @@ if skipKitValidation: opts += ['-ikv'] - return Test("SPECjvm2008", "SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + opts + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC'], defaultCwd=specjvm2008) + return Test("SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + opts + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC'], defaultCwd=specjvm2008) def getDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=[]): checks = [] @@ -143,10 +143,12 @@ dacapoSuccess = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) PASSED in ([0-9]+) msec =====$") dacapoFail = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) FAILED (warmup|) =====$") dacapoTime = re.compile(r"===== DaCapo 9\.12 (?P[a-zA-Z0-9_]+) PASSED in (?P