# HG changeset patch # User Thomas Wuerthinger # Date 1398991526 -7200 # Node ID 5ecbed00da232caa1add3b89e9a909986badbb71 # Parent b3fbf52f34be0a0bcb8aa97de95ae17b6574eb16# Parent a20be10ad437e8037dec7712dab8a8718332d4ac Merge. diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java Fri May 02 02:45:26 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,16 +33,16 @@ /** * Keys. */ - private Register[] registers; + private final Register[] registers; /** * Slot indexes relative to stack pointer. */ - private int[] slots; + private final int[] slots; /** * Creates a map from registers to frame slots. - * + * * @param registers the keys in the map * @param slots frame slot index for each register in {@code registers} */ @@ -55,6 +55,21 @@ } /** + * Gets the frame slot index for a given register. + * + * @param register register to get the frame slot index for + * @return frame slot index + */ + public int registerToSlot(Register register) { + for (int i = 0; i < registers.length; i++) { + if (register.equals(registers[i])) { + return slots[i]; + } + } + throw new IllegalArgumentException(register + " not saved by this layout: " + this); + } + + /** * Gets this layout information as a {@link Map} from registers to slots. */ public Map registersToSlots(boolean sorted) { diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Fri May 02 02:45:26 2014 +0200 @@ -40,24 +40,6 @@ } }; - /** - * This is the Value of a node which was matched as part of a complex match. The value isn't - * actually useable but this marks it as having been evaluated. - */ - @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) { - - @Override - public String toString() { - return "INTERIOR_MATCH"; - } - - @Override - public boolean equals(Object other) { - // This class is a singleton - return other != null && getClass() == other.getClass(); - } - }; - private final Kind kind; private final PlatformKind platformKind; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Fri May 02 02:45:26 2014 +0200 @@ -79,6 +79,14 @@ } } + public final void movptr(Register dst, AMD64Address src) { + movq(dst, src); + } + + public final void movptr(AMD64Address dst, Register src) { + movq(dst, src); + } + public final void movptr(AMD64Address dst, int src) { movslq(dst, src); } @@ -277,7 +285,7 @@ /** * Emit code to save a given set of callee save registers in the {@linkplain CalleeSaveLayout * CSA} within the frame. - * + * * @param csl the description of the CSA * @param frameToCSA offset from the frame pointer to the CSA */ diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Fri May 02 02:45:26 2014 +0200 @@ -182,20 +182,16 @@ // Only imm32 as long return null; } - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access))); - gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); - return null; - } + return builder -> { + gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; }; } else { - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access))); - gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); - return null; - } + return builder -> { + gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; }; } } @@ -320,8 +316,6 @@ throw GraalInternalError.shouldNotReachHere(); } - static Object lock = new Object(); - private AMD64Arithmetic getOp(ValueNode operation, Access access) { Kind memoryKind = getMemoryKind(access); if (operation.getClass() == IntegerAddNode.class) { @@ -391,17 +385,10 @@ return null; } - @MatchRule("(If (IntegerTest=compare Read=access value))") - @MatchRule("(If (IntegerTest=compare FloatingRead=access value))") - public static class IfIntegerTest extends AMD64MatchGenerator { - IfNode root; - Access access; - ValueNode value; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return gen.emitIntegerTestBranchMemory(root, value, access); - } + @MatchRule("(If (IntegerTest Read=access value))") + @MatchRule("(If (IntegerTest FloatingRead=access value))") + public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) { + return emitIntegerTestBranchMemory(root, value, access); } @MatchRule("(If (IntegerEquals=compare value Read=access))") @@ -414,62 +401,32 @@ @MatchRule("(If (FloatEquals=compare value FloatingRead=access))") @MatchRule("(If (FloatLessThan=compare value Read=access))") @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))") - public static class IfCompareMemory extends AMD64MatchGenerator { - IfNode root; - Access access; - ValueNode value; - CompareNode compare; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return gen.emitCompareBranchMemory(root, compare, value, access); - } + public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) { + return emitCompareBranchMemory(root, compare, value, access); } @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))") - public static class RotateLeftConstant extends AMD64MatchGenerator { - LeftShiftNode lshift; - UnsignedRightShiftNode rshift; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) { - return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(lshift.x()), gen.operand(lshift.y())); - } - return null; + public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) { + if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) { + return builder -> getLIRGeneratorTool().emitRol(operand(lshift.x()), operand(lshift.y())); } - + return null; } - @MatchRule("(Or (LeftShift=lshift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))") - public static class RotateRightVariable extends AMD64MatchGenerator { - ValueNode value; - ValueNode shiftAmount; - ConstantNode delta; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { - return builder -> gen.getLIRGeneratorTool().emitRor(gen.operand(value), gen.operand(shiftAmount)); - } - return null; + @MatchRule("(Or (LeftShift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))") + public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) { + if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { + return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount)); } - + return null; } @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))") - public static class RotateLeftVariable extends AMD64MatchGenerator { - ValueNode value; - ValueNode shiftAmount; - ConstantNode delta; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { - return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(value), gen.operand(shiftAmount)); - } - return null; + public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) { + if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { + return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount)); } + return null; } @MatchRule("(IntegerAdd value Read=access)") @@ -490,121 +447,61 @@ @MatchRule("(Or value FloatingRead=access)") @MatchRule("(Xor value FloatingRead=access)") @MatchRule("(And value FloatingRead=access)") - public static class BinaryRead extends AMD64MatchGenerator { - BinaryNode root; - Access access; - ValueNode value; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - AMD64Arithmetic op = gen.getOp(root, access); - if (op != null) { - return builder -> gen.getLIRGeneratorTool().emitBinaryMemory(op, gen.getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(value)), gen.makeAddress(access), - gen.getState(access)); - } - return null; + public ComplexMatchResult binaryRead(BinaryNode root, ValueNode value, Access access) { + AMD64Arithmetic op = getOp(root, access); + if (op != null) { + return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access)); } + return null; } @MatchRule("(Write Narrow=narrow value)") - public static class WriteNarrow extends AMD64MatchGenerator { - WriteNode root; - NarrowNode narrow; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return new ComplexMatchResult() { - @Override - public Value evaluate(NodeLIRBuilder builder) { - PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(root.value().stamp()); - Value address = root.location().generateAddress(builder, gen.getLIRGeneratorTool(), gen.operand(root.object())); - Value v = gen.operand(narrow.getInput()); - gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(root)); - return null; - } - }; - } + public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) { + return builder -> { + PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp()); + Value address = root.location().generateAddress(builder, getLIRGeneratorTool(), operand(root.object())); + Value v = operand(narrow.getInput()); + getLIRGeneratorTool().emitStore(writeKind, address, v, state(root)); + return null; + }; } @MatchRule("(SignExtend Read=access)") @MatchRule("(SignExtend FloatingRead=access)") - public static class SignExtend extends AMD64MatchGenerator { - Access access; - SignExtendNode root; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return gen.emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); - } - } - - static abstract class AMD64MatchGenerator implements MatchGenerator { - public AMD64MatchGenerator() { - } - - public ComplexMatchResult match(NodeLIRBuilder gen) { - return match((AMD64NodeLIRBuilder) gen); - } - - abstract public ComplexMatchResult match(AMD64NodeLIRBuilder gen); + public ComplexMatchResult signExtend(SignExtendNode root, Access access) { + return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); } @MatchRule("(ZeroExtend Read=access)") @MatchRule("(ZeroExtend FloatingRead=access)") - public static class ZeroExtend extends AMD64MatchGenerator { - Access access; - ZeroExtendNode root; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - Kind memoryKind = gen.getMemoryKind(access); - if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) { - /* - * The memory being read from is signed and smaller than the result size so this is - * a sign extension to inputBits followed by a zero extension to resultBits which - * can't be expressed in a memory operation. - */ - return null; - } - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder unused) { - return gen.getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), gen.makeAddress(access), gen.getState(access)); - } - }; + public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) { + Kind memoryKind = getMemoryKind(access); + if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) { + /* + * The memory being read from is signed and smaller than the result size so this is a + * sign extension to inputBits followed by a zero extension to resultBits which can't be + * expressed in a memory operation. + */ + return null; } + return builder -> getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), makeAddress(access), getState(access)); } @MatchRule("(FloatConvert Read=access)") @MatchRule("(FloatConvert FloatingRead=access)") - public static class FloatConvert extends AMD64MatchGenerator { - Access access; - FloatConvertNode root; + public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) { + return builder -> emitFloatConvertMemory(root, access); - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - return gen.emitFloatConvertMemory(root, access); - } - }; - } } @MatchRule("(Reinterpret Read=access)") @MatchRule("(Reinterpret FloatingRead=access)") - public static class Reinterpret extends AMD64MatchGenerator { - Access access; - ReinterpretNode root; + public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) { + return builder -> { + PlatformKind kind = getLIRGeneratorTool().getPlatformKind(root.stamp()); + return emitReinterpretMemory(kind, access); + }; - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - PlatformKind kind = gen.getLIRGeneratorTool().getPlatformKind(root.stamp()); - return gen.emitReinterpretMemory(kind, access); - } - }; - } } @Override diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Fri May 02 02:45:26 2014 +0200 @@ -70,6 +70,8 @@ return enabled; } }; + @Option(help = "Enable more verbose log output when available") + public static final OptionValue LogVerbose = new OptionValue<>(false); // @formatter:on public static boolean areDebugScopePatternsEnabled() { @@ -150,7 +152,7 @@ /** * Extracts a {@link JavaMethod} from an opaque debug context. - * + * * @return the {@link JavaMethod} represented by {@code context} or null */ public static JavaMethod asJavaMethod(Object context) { diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Fri May 02 02:45:26 2014 +0200 @@ -170,7 +170,7 @@ * ValueNodes. */ public void setMatchResult(ValueNode x, Value operand) { - assert operand.equals(Value.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; + assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; assert operand instanceof ComplexMatchValue || x.usages().count() == 1 : "interior matches must be single user"; assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice"; assert !(x instanceof VirtualObjectNode); @@ -237,7 +237,7 @@ throw new GraalGraphInternalError(e).addContext(instr); } } - } else if (Value.INTERIOR_MATCH.equals(operand)) { + } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) { // Doesn't need to be evaluated Debug.log("interior match for %s", valueNode); } else if (operand instanceof ComplexMatchValue) { @@ -285,7 +285,7 @@ List statements = matchRules.get(node.getClass()); if (statements != null) { for (MatchStatement statement : statements) { - if (statement.generate(this, node, nodes)) { + if (statement.generate(this, index, node, nodes)) { // Found a match so skip to the next break; } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java Fri May 02 02:45:26 2014 +0200 @@ -25,10 +25,10 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; -/* - * A closure that can be evaluated to produce the LIR for some complex match. Using a closure - * allows normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes - * evaluated at the proper time. +/** + * A closure that can be evaluated to produce the LIR for some complex match. Using a closure allows + * normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes evaluated at + * the proper time. */ public interface ComplexMatchResult { Value evaluate(NodeLIRBuilder gen); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Fri May 02 02:45:26 2014 +0200 @@ -31,10 +31,25 @@ * usually occur here. */ public class ComplexMatchValue extends Value { + private static final long serialVersionUID = -4734670273590368770L; + /** - * + * This is the Value of a node which was matched as part of a complex match. The value isn't + * actually useable but this marks it as having been evaluated. */ - private static final long serialVersionUID = -4734670273590368770L; + @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) { + + @Override + public String toString() { + return "INTERIOR_MATCH"; + } + + @Override + public boolean equals(Object other) { + // This class is a singleton + return other != null && getClass() == other.getClass(); + } + }; final ComplexMatchResult result; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java Fri May 02 02:45:26 2014 +0200 @@ -30,34 +30,34 @@ * Helper class to describe the matchable nodes in the core Graal IR. These could possibly live in * their respective classes but for simplicity in the {@link MatchProcessor} they are grouped here. */ -@MatchableNode(shortName = "Constant", value = ConstantNode.class, inputs = 0) -@MatchableNode(shortName = "FloatConvert", value = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "FloatSub", value = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "FloatingRead", value = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) -@MatchableNode(shortName = "If", value = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class) -@MatchableNode(shortName = "IntegerSub", value = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "LeftShift", value = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "Narrow", value = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "Read", value = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) -@MatchableNode(shortName = "Reinterpret", value = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class) -@MatchableNode(shortName = "SignExtend", value = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "UnsignedRightShift", value = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "Write", value = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class) -@MatchableNode(shortName = "ZeroExtend", value = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "And", value = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatAdd", value = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatEquals", value = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatLessThan", value = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatMul", value = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerAdd", value = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerBelowThan", value = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerEquals", value = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerLessThan", value = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerMul", value = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerTest", value = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "ObjectEquals", value = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "Or", value = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "Xor", value = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = ConstantNode.class, inputs = 0) +@MatchableNode(nodeClass = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) +@MatchableNode(nodeClass = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class) +@MatchableNode(nodeClass = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) +@MatchableNode(nodeClass = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class) +@MatchableNode(nodeClass = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class) +@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) public class GraalMatchableNodes { public static class BinaryNodeAdapter extends MatchNodeAdapter { @Override diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Fri May 02 02:45:26 2014 +0200 @@ -22,10 +22,10 @@ */ package com.oracle.graal.compiler.match; -import java.lang.reflect.*; +import static com.oracle.graal.compiler.GraalDebugConfig.*; + import java.util.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.match.MatchPattern.Result; @@ -38,24 +38,41 @@ * Container for state captured during a match. */ public class MatchContext { - private final ArrayList consumed = new ArrayList<>(); - private final List nodes; + private final ValueNode root; - private List names; - private List> types; - private List values; + + private final List nodes; + private final MatchStatement rule; + + private Map namedNodes; + + private ArrayList consumed; + private int startIndex; + private int endIndex; + private final NodeLIRBuilder builder; - public MatchContext(NodeLIRBuilder builder, MatchStatement rule, ValueNode node, List nodes) { + private static class NamedNode { + final Class type; + final ValueNode value; + + NamedNode(Class type, ValueNode value) { + this.type = type; + this.value = value; + } + } + + public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List nodes) { this.builder = builder; this.rule = rule; this.root = node; this.nodes = nodes; - // The root should be the last index since all the inputs must be scheduled before. - startIndex = endIndex = nodes.indexOf(node); + assert index == nodes.indexOf(node); + // The root should be the last index since all the inputs must be scheduled before it. + startIndex = endIndex = index; } public ValueNode getRoot() { @@ -63,19 +80,16 @@ } public Result captureNamedValue(String name, Class type, ValueNode value) { - if (names == null) { - names = new ArrayList<>(2); - values = new ArrayList<>(2); - types = new ArrayList<>(2); + if (namedNodes == null) { + namedNodes = new HashMap<>(2); } - int index = names.indexOf(name); - if (index == -1) { - names.add(name); - values.add(value); - types.add(type); + NamedNode current = namedNodes.get(name); + if (current == null) { + current = new NamedNode(type, value); + namedNodes.put(name, current); return Result.OK; } else { - if (values.get(index) != value) { + if (current.value != value || current.type != type) { return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern()); } return Result.OK; @@ -85,20 +99,19 @@ public Result validate() { // Ensure that there's no unsafe work in between these operations. for (int i = startIndex; i <= endIndex; i++) { - ScheduledNode node = getNodes().get(i); + ScheduledNode node = nodes.get(i); if (node instanceof ConstantNode || node instanceof LocationNode || node instanceof VirtualObjectNode || node instanceof ParameterNode) { // these can be evaluated lazily so don't worry about them. This should probably be // captured by some interface that indicates that their generate method is empty. continue; - } else if (!consumed.contains(node) && node != root) { - // This is too verbose for normal logging. - // Debug.log("unexpected node %s", node); - // for (int j = startIndex; j <= endIndex; j++) { - // ScheduledNode theNode = getNodes().get(j); - // Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" : - // " ", - // theNode.usages().count(), theNode); - // } + } else if (consumed == null || !consumed.contains(node) && node != root) { + if (LogVerbose.getValue()) { + Debug.log("unexpected node %s", node); + for (int j = startIndex; j <= endIndex; j++) { + ScheduledNode theNode = nodes.get(j); + Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode); + } + } return Result.NOT_SAFE(node, rule.getPattern()); } } @@ -106,56 +119,24 @@ } /** - * Transfers the captured value into the MatchGenerator instance. The reflective information - * should really be generated and checking during construction of the MatchStatement but this is - * ok for now. - */ - public void transferState(MatchGenerator generator) { - try { - for (int i = 0; i < names.size(); i++) { - String name = names.get(i); - try { - Field field = generator.getClass().getDeclaredField(name); - field.setAccessible(true); - field.set(generator, values.get(i)); - } catch (NoSuchFieldException e) { - // Doesn't exist so the generator doesn't care about the value. - } - } - } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { - throw new GraalInternalError(e); - } - try { - Field field = generator.getClass().getDeclaredField("root"); - field.setAccessible(true); - field.set(generator, getRoot()); - } catch (NoSuchFieldException e) { - // Doesn't exist - } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) { - throw new GraalInternalError(e); - } - } - - public void setResult(ComplexMatchResult result) { - setResult(new ComplexMatchValue(result)); - } - - /** * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result. * During final LIR generation it will be evaluated to produce the actual LIR value. * * @param result */ - public void setResult(ComplexMatchValue result) { + public void setResult(ComplexMatchResult result) { + ComplexMatchValue value = new ComplexMatchValue(result); Debug.log("matched %s %s", rule.getName(), rule.getPattern()); - // Debug.log("%s", rule.formatMatch(root)); - for (ValueNode node : consumed) { - // All the interior nodes should be skipped during the normal doRoot calls in - // NodeLIRBuilder so mark them as interior matches. The root of the match will get a - // closure which will be evaluated to produce the final LIR. - getBuilder().setMatchResult(node, Value.INTERIOR_MATCH); + Debug.log("with nodes %s", rule.formatMatch(root)); + if (consumed != null) { + for (ValueNode node : consumed) { + // All the interior nodes should be skipped during the normal doRoot calls in + // NodeLIRBuilder so mark them as interior matches. The root of the match will get a + // closure which will be evaluated to produce the final LIR. + builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH); + } } - getBuilder().setMatchResult(root, result); + builder.setMatchResult(root, value); } /** @@ -164,28 +145,43 @@ * @return Result.OK if the node can be safely consumed. */ public Result consume(ValueNode node) { - if (node.usages().count() != 1) { - return Result.TOO_MANY_USERS(node, rule.getPattern()); - } + assert node.usages().count() <= 1 : "should have already been checked"; - if (getBuilder().hasOperand(node)) { + if (builder.hasOperand(node)) { return Result.ALREADY_USED(node, rule.getPattern()); } - int index = getNodes().indexOf(node); + int index = nodes.indexOf(node); if (index == -1) { return Result.NOT_IN_BLOCK(node, rule.getPattern()); } startIndex = Math.min(startIndex, index); + if (consumed == null) { + consumed = new ArrayList<>(2); + } consumed.add(node); return Result.OK; } - private NodeLIRBuilder getBuilder() { - return builder; + /** + * Return the named node. It's an error if the + * + * @param name the name of a node in the match rule + * @return the matched node + * @throws GraalInternalError is the named node doesn't exist. + */ + public ValueNode namedNode(String name) { + if (namedNodes != null) { + NamedNode value = namedNodes.get(name); + if (value != null) { + return value.value; + } + } + throw new GraalInternalError("missing node %s", name); } - private List getNodes() { - return nodes; + @Override + public String toString() { + return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : ""); } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Fri May 02 02:45:26 2014 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.compiler.match; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; @@ -47,7 +48,9 @@ */ static class Result { final MatchResultCode code; + final ScheduledNode node; + final MatchPattern matcher; Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) { @@ -56,29 +59,42 @@ this.matcher = matcher; } + private static final DebugMetric MatchResult_WRONG_CLASS = Debug.metric("MatchResult_WRONG_CLASS"); + private static final DebugMetric MatchResult_NAMED_VALUE_MISMATCH = Debug.metric("MatchResult_NAMED_VALUE_MISMATCH"); + private static final DebugMetric MatchResult_TOO_MANY_USERS = Debug.metric("MatchResult_TOO_MANY_USERS"); + private static final DebugMetric MatchResult_NOT_IN_BLOCK = Debug.metric("MatchResult_NOT_IN_BLOCK"); + private static final DebugMetric MatchResult_NOT_SAFE = Debug.metric("MatchResult_NOT_SAFE"); + private static final DebugMetric MatchResult_ALREADY_USED = Debug.metric("MatchResult_ALREADY_USED"); + static final Result OK = new Result(MatchResultCode.OK, null, null); static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) { + MatchResult_WRONG_CLASS.increment(); return new Result(MatchResultCode.WRONG_CLASS, node, matcher); } static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) { + MatchResult_NAMED_VALUE_MISMATCH.increment(); return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher); } static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) { + MatchResult_TOO_MANY_USERS.increment(); return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher); } static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) { + MatchResult_NOT_IN_BLOCK.increment(); return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher); } static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) { + MatchResult_NOT_SAFE.increment(); return new Result(MatchResultCode.NOT_SAFE, node, matcher); } static Result ALREADY_USED(ValueNode node, MatchPattern matcher) { + MatchResult_ALREADY_USED.increment(); return new Result(MatchResultCode.ALREADY_USED, node, matcher); } @@ -143,14 +159,32 @@ return nodeClass; } - Result match(ValueNode node, MatchContext context) { - return matchTree(node, context, true); + private Result matchType(ValueNode node) { + if (nodeClass != null && node.getClass() != nodeClass) { + return Result.WRONG_CLASS(node, this); + } + return Result.OK; } - private Result matchTree(ValueNode node, MatchContext context, boolean atRoot) { - Result result = Result.OK; - if (nodeClass != null && node.getClass() != nodeClass) { - return Result.WRONG_CLASS(node, this); + /** + * Match any named nodes and ensure that the consumed nodes can be safely merged. + * + * @param node + * @param context + * @return Result.OK is the pattern can be safely matched. + */ + Result matchUsage(ValueNode node, MatchContext context) { + Result result = matchUsage(node, context, true); + if (result == Result.OK) { + result = context.validate(); + } + return result; + } + + private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) { + Result result = matchType(node); + if (result != Result.OK) { + return result; } if (singleUser && !atRoot) { result = context.consume(node); @@ -164,9 +198,43 @@ } if (first != null) { - result = first.matchTree(adapter.getFirstInput(node), context, false); + result = first.matchUsage(adapter.getFirstInput(node), context, false); if (result == Result.OK && second != null) { - result = second.matchTree(adapter.getSecondInput(node), context, false); + result = second.matchUsage(adapter.getSecondInput(node), context, false); + } + } + + return result; + } + + /** + * Recursively match the shape of the tree without worry about named values. Most matches fail + * at this point so it's performed first. + * + * @param node + * @param statement + * @return Result.OK if the shape of the pattern matches. + */ + public Result matchShape(ValueNode node, MatchStatement statement) { + return matchShape(node, statement, true); + } + + private Result matchShape(ValueNode node, MatchStatement statement, boolean atRoot) { + Result result = matchType(node); + if (result != Result.OK) { + return result; + } + + if (singleUser && !atRoot) { + if (node.usages().count() > 1) { + return Result.TOO_MANY_USERS(node, statement.getPattern()); + } + } + + if (first != null) { + result = first.matchShape(adapter.getFirstInput(node), statement, false); + if (result == Result.OK && second != null) { + result = second.matchShape(adapter.getSecondInput(node), statement, false); } } @@ -195,7 +263,8 @@ String pre = first != null || second != null ? "(" : ""; String post = first != null || second != null ? ")" : ""; String nodeName = nodeClass.getSimpleName(); - return pre + nodeName + (name != null ? "=\"" + name + "\"" : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post; + nodeName = nodeName.substring(0, nodeName.length() - 4); + return pre + nodeName + (name != null ? "=" + name : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post; } } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Fri May 02 02:45:26 2014 +0200 @@ -30,6 +30,7 @@ import javax.lang.model.*; import javax.lang.model.element.*; import javax.lang.model.type.*; +import javax.lang.model.util.*; import javax.tools.Diagnostic.Kind; import javax.tools.*; @@ -63,14 +64,23 @@ private static class RuleParseError extends RuntimeException { private static final long serialVersionUID = 6456128283609257490L; - RuleParseError(String message) { - super(message); + RuleParseError(String format, Object... args) { + super(String.format(format, args)); } } private class RuleParser { - final String[] tokens; - int current; + private ArrayList capturedTypes = new ArrayList<>(); + + private ArrayList capturedNames = new ArrayList<>(); + + private final String[] tokens; + + private int current; + + private MatchDescriptor matchDescriptor; + + private final Set originatingElements = new HashSet<>(); RuleParser(String rule) { Matcher m = tokenizer.matcher(rule); @@ -82,16 +92,29 @@ m.region(m.end(), m.regionEnd()); } if (end != m.regionEnd()) { - throw new RuleParseError("unexpected tokens :" + rule.substring(m.end(), m.regionEnd())); + throw new RuleParseError("Unnexpected tokens :" + rule.substring(m.end(), m.regionEnd())); } tokens = list.toArray(new String[0]); + + matchDescriptor = parseExpression(); + if (!done()) { + throw new RuleParseError("didn't consume all tokens"); + } + capturedNames.add(0, "root"); + capturedTypes.add(0, matchDescriptor.nodeType); } String next() { return tokens[current++]; } - String peek() { + String peek(String name) { + if (current >= tokens.length) { + if (name == null) { + throw new RuleParseError("Out of tokens"); + } + throw new RuleParseError("Out of tokens looking for %s", name); + } return tokens[current]; } @@ -99,13 +122,13 @@ return current == tokens.length; } - private MatchDescriptor parseSexp() { - if (peek().equals("(")) { + private MatchDescriptor parseExpression() { + if (peek("(").equals("(")) { next(); MatchDescriptor descriptor = parseType(true); for (int n = 0; n < descriptor.nodeType.inputs; n++) { - if (peek().equals("(")) { - descriptor.inputs[n] = parseSexp(); + if (peek("(").equals("(")) { + descriptor.inputs[n] = parseExpression(); } else { descriptor.inputs[n] = parseType(false); } @@ -115,46 +138,70 @@ throw new RuleParseError("not enough inputs for " + descriptor.name); } } - if (peek().equals(")")) { + if (peek(")").equals(")")) { next(); return descriptor; } } - throw new RuleParseError("didn't swallow sexp at: " + peek()); + throw new RuleParseError("Extra tokens following match pattern: " + peek(null)); } - private MatchDescriptor parseType(boolean sexp) { + private MatchDescriptor parseType(boolean forExpression) { TypeDescriptor type = null; String name = null; - if (Character.isUpperCase(peek().charAt(0))) { + if (Character.isUpperCase(peek("node type or name").charAt(0))) { String token = next(); - type = types.get(token); + type = knownTypes.get(token); if (type == null) { - throw new RuleParseError("unknown node type: " + token); + throw new RuleParseError("Unknown node type: " + token); } - if (peek().equals("=")) { + if (peek("=").equals("=")) { next(); name = next(); } - } else { + originatingElements.addAll(type.originatingElements); + } else if (Character.isLowerCase(peek("name").charAt(0))) { name = next(); - type = null; + type = valueType; + } else { + throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null)); } - return new MatchDescriptor(type, name, sexp); + if (name != null) { + if (!capturedNames.contains(name)) { + capturedNames.add(name); + capturedTypes.add(type); + } else { + int index = capturedNames.indexOf(name); + if (capturedTypes.get(index) != type) { + throw new RuleParseError("Captured node \"%s\" has differing types", name); + } + } + } + return new MatchDescriptor(type, name, forExpression); } - ArrayList generateVariants() { - MatchDescriptor descriptor = parseSexp(); - if (!done()) { - throw new RuleParseError("didn't consume all tokens"); - } - return descriptor.generateVariants(); + List generateVariants() { + return matchDescriptor.generateVariants(); + } + + /** + * + * @return the list of node types which are captured by name + */ + public ArrayList capturedTypes() { + return capturedTypes; + } + + public ArrayList capturedNames() { + return capturedNames; } } static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*"); static class TypeDescriptor { + final TypeMirror mirror; + /** * The name uses in match expressions to refer to this type. */ @@ -192,7 +239,10 @@ */ final boolean cloneable; - TypeDescriptor(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { + final Set originatingElements = new HashSet<>(); + + TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { + this.mirror = mirror; this.shortName = shortName; this.nodeClass = nodeClass; this.nodePackage = nodePackage; @@ -204,14 +254,28 @@ } } - HashMap types = new HashMap<>(); - ArrayList packages = new ArrayList<>(); + /** + * The types which are know for purpose of parsing MatchRule expressions. + */ + Map knownTypes = new HashMap<>(); + + /** + * The set of packages which must be imported to refer to the known classes. + */ + List requiredPackages = new ArrayList<>(); - private void declareType(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { - TypeDescriptor descriptor = new TypeDescriptor(shortName, nodeClass, nodePackage, inputs, adapter, commutative); - types.put(shortName, descriptor); - if (!packages.contains(descriptor.nodePackage)) { - packages.add(descriptor.nodePackage); + /** + * The automatically generated wrapper class for a method based MatchRule. + */ + private Map invokers = new LinkedHashMap<>(); + private TypeDescriptor valueType; + + private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative, Element element) { + TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, adapter, commutative); + descriptor.originatingElements.add(element); + knownTypes.put(shortName, descriptor); + if (!requiredPackages.contains(descriptor.nodePackage)) { + requiredPackages.add(descriptor.nodePackage); } } @@ -226,22 +290,28 @@ throw new GraalInternalError("can't find package for %s", type); } - static class MatchDescriptor { + class MatchDescriptor { TypeDescriptor nodeType; String name; MatchDescriptor[] inputs; - MatchDescriptor(TypeDescriptor nodeType, String name, boolean sexp) { + MatchDescriptor(TypeDescriptor nodeType, String name, boolean forExpression) { this.nodeType = nodeType; this.name = name; - if (sexp) { + if (forExpression) { this.inputs = new MatchDescriptor[nodeType.inputs]; } else { this.inputs = new MatchDescriptor[0]; } } - ArrayList generateVariants() { + /** + * Recursively generate all the variants of this rule pattern. Currently that just means to + * swap the inputs for commutative rules, producing all possible permutations. + * + * @return a list of Strings which will construct pattern matchers for this rule. + */ + List generateVariants() { String prefix = formatPrefix(); String suffix = formatSuffix(); ArrayList variants = new ArrayList<>(); @@ -266,7 +336,7 @@ } private String formatPrefix() { - if (nodeType == null) { + if (nodeType == valueType) { return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null"); } else { return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null"); @@ -291,15 +361,25 @@ } + /** + * Strip the package off a class name leaving the full class name including any outer classes. + */ + static String fullClassName(Element element) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE : element; + String pkg = findPackage(element); + return ((TypeElement) element).getQualifiedName().toString().substring(pkg.length() + 1); + } + private void createFiles(MatchRuleDescriptor info) { String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); Name topDeclaringClass = info.topDeclaringType.getSimpleName(); - String optionsClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName(); + String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName(); Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); + Types typeUtils = processingEnv.getTypeUtils(); Filer filer = processingEnv.getFiler(); - try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { + try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) { out.println("// CheckStyle: stop header check"); out.println("// GENERATED CONTENT - DO NOT EDIT"); @@ -307,29 +387,56 @@ out.println("package " + pkg + ";"); out.println(""); out.println("import java.util.*;"); + out.println("import java.lang.reflect.*;"); out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;"); + out.println("import " + GraalInternalError.class.getName() + ";"); out.println("import " + NodeLIRBuilder.class.getName() + ";"); - for (String p : packages) { + for (String p : requiredPackages) { out.println("import " + p + ".*;"); } out.println(""); - out.println("public class " + optionsClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {"); + out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {"); + + // Generate declarations for the reflective invocation of the code generation methods. + for (MethodInvokerItem invoker : invokers.values()) { + StringBuilder args = new StringBuilder(); + StringBuilder types = new StringBuilder(); + int count = invoker.fields.size(); + for (VariableElement arg : invoker.fields) { + args.append('"'); + args.append(arg.getSimpleName()); + args.append('"'); + types.append(fullClassName(typeUtils.asElement(arg.asType()))); + types.append(".class"); + if (count-- > 1) { + args.append(", "); + types.append(", "); + } + } + out.printf(" private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args); + out.printf(" private static final Method %s;\n", invoker.reflectiveMethodName()); + out.printf(" static {\n"); + out.printf(" Method result = null;\n"); + out.printf(" try {\n"); + out.printf(" result = %s.class.getDeclaredMethod(\"%s\", %s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types); + out.printf(" } catch (Exception e) {\n"); + out.printf(" throw new GraalInternalError(e);\n"); + out.printf(" }\n"); + out.printf(" %s = result;\n", invoker.reflectiveMethodName()); + out.printf(" }\n"); + + out.println(); + + } + String desc = MatchStatement.class.getSimpleName(); out.println(" // CheckStyle: stop line length check"); - out.println(" private static final List<" + desc + "> options = Collections.unmodifiableList(Arrays.asList("); + out.println(" private static final List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList("); int i = 0; - for (MatchRuleItem option : info.options) { - String optionValue; - if (option.field.getModifiers().contains(Modifier.PRIVATE)) { - optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; - } else { - optionValue = option.declaringClass + "." + option.field.getSimpleName(); - } - String name = option.name; - Name fieldName = option.field.getSimpleName(); - String comma = i == info.options.size() - 1 ? "" : ","; - out.printf(" new MatchStatement(\"%s\", %s, %s.class)%s\n", fieldName, name, optionValue, comma); + for (MatchRuleItem matchRule : info.matchRules) { + String comma = i == info.matchRules.size() - 1 ? "" : ","; + out.printf(" %s%s\n", matchRule.ruleBuilder(), comma); i++; } out.println(" ));"); @@ -342,13 +449,13 @@ out.println(); out.println(" @Override"); out.println(" public List<" + desc + "> statements() {"); - out.println(" return options;"); + out.println(" return statements;"); out.println(" }"); out.println("}"); } try { - createProviderFile(pkg, optionsClassName, originatingElements); + createProviderFile(pkg, matchStatementClassName, originatingElements); } catch (IOException e) { processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType); } @@ -378,34 +485,57 @@ } } - static class MatchRuleItem implements Comparable { + /** + * Used to generate the MatchStatement constructor invocation. + */ + static class MatchRuleItem { + private final String matchPattern; + private final MethodInvokerItem invoker; - final String name; - final String declaringClass; - final TypeElement field; - - public MatchRuleItem(String name, String declaringClass, TypeElement field) { - this.name = name; - this.declaringClass = declaringClass; - this.field = field; + public MatchRuleItem(String matchPattern, MethodInvokerItem invoker) { + this.matchPattern = matchPattern; + this.invoker = invoker; } - @Override - public int compareTo(MatchRuleItem other) { - return name.compareTo(other.name); + /** + * @return a string which will construct the MatchStatement instance to match this pattern. + */ + public String ruleBuilder() { + return String.format("new MatchStatement(\"%s\", %s, %s, %s)", invoker.name, matchPattern, invoker.reflectiveMethodName(), invoker.argumentsListName()); + } + } + + /** + * Used to generate the declarations needed for reflective invocation of the code generation + * method. + */ + static class MethodInvokerItem { + final String name; + final String nodeLIRBuilderClass; + final String methodName; + final List fields; + + MethodInvokerItem(String name, String nodeLIRBuilderClass, String methodName, List fields) { + this.name = name; + this.nodeLIRBuilderClass = nodeLIRBuilderClass; + this.methodName = methodName; + this.fields = fields; } - @Override - public String toString() { - return declaringClass + "." + field; + String reflectiveMethodName() { + return methodName + "_invoke"; + } + + String argumentsListName() { + return methodName + "_arguments"; } } static class MatchRuleDescriptor { final TypeElement topDeclaringType; - final List options = new ArrayList<>(); - final Set originatingElements = new HashSet<>(); + final List matchRules = new ArrayList<>(); + private final Set originatingElements = new HashSet<>(); public MatchRuleDescriptor(TypeElement topDeclaringType) { this.topDeclaringType = topDeclaringType; @@ -428,6 +558,11 @@ } try { + // Define a TypeDescriptor the generic node but don't enter it into the nodeTypes table + // since it shouldn't mentioned in match rules. + TypeMirror mirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType(); + valueType = new TypeDescriptor(mirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), 0, null, false); + // Import default definitions processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName())); for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodeImport.class)) { @@ -457,7 +592,7 @@ } } catch (Throwable t) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t); + processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2))); } return true; @@ -468,107 +603,170 @@ */ private void processMatchableNode(Element element) { if (!processedMatchableNode.contains(element)) { - processedMatchableNode.add(element); - TypeElement topDeclaringType = topDeclaringType(element); - MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class); - for (MatchableNode matchable : matchables) { - String nodeClass; - String nodePackage; - String shortName = matchable.shortName(); - TypeMirror nodeClassMirror = null; - try { - matchable.value(); - } catch (MirroredTypeException e) { - nodeClassMirror = e.getTypeMirror(); - } - if (nodeClassMirror == null) { - throw new GraalInternalError("Can't get mirror for node class %s", element); + try { + processedMatchableNode.add(element); + TypeElement topDeclaringType = topDeclaringType(element); + MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class); + for (MatchableNode matchable : matchables) { + String nodeClass; + String nodePackage; + TypeMirror nodeClassMirror = null; + try { + matchable.nodeClass(); + } catch (MirroredTypeException e) { + nodeClassMirror = e.getTypeMirror(); + } + if (nodeClassMirror == null) { + throw new GraalInternalError("Can't get mirror for node class %s", element); + } + if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) { + nodeClass = topDeclaringType.getQualifiedName().toString(); + } else { + nodeClass = nodeClassMirror.toString(); + } + nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass)); + assert nodeClass.startsWith(nodePackage); + nodeClass = nodeClass.substring(nodePackage.length() + 1); + assert nodeClass.endsWith("Node"); + String shortName = nodeClass.substring(0, nodeClass.length() - 4); + + TypeMirror nodeAdapterMirror = null; + try { + matchable.adapter(); + } catch (MirroredTypeException e) { + nodeAdapterMirror = e.getTypeMirror(); + } + if (nodeAdapterMirror == null) { + throw new GraalInternalError("Can't get mirror for adapter %s", element); + } + String nodeAdapter = null; + if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) { + nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString()); + } + + declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative(), element); } - if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) { - nodeClass = topDeclaringType.getQualifiedName().toString(); - } else { - nodeClass = nodeClassMirror.toString(); - } - nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass)); - assert nodeClass.startsWith(nodePackage); - nodeClass = nodeClass.substring(nodePackage.length() + 1); - - TypeMirror nodeAdapterMirror = null; - try { - matchable.adapter(); - } catch (MirroredTypeException e) { - nodeAdapterMirror = e.getTypeMirror(); - } - if (nodeAdapterMirror == null) { - throw new GraalInternalError("Can't get mirror for adapter %s", element); - } - String nodeAdapter = null; - if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) { - nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString()); - } - - declareType(shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative()); + } catch (Throwable t) { + reportExceptionThrow(element, t); } } } + private void reportExceptionThrow(Element element, Throwable t) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)), element); + } + private void processMatchRule(Map map, Element element) { if (!processedMatchRule.contains(element)) { - processedMatchRule.add(element); - TypeElement topDeclaringType = topDeclaringType(element); - MatchRuleDescriptor options = map.get(topDeclaringType); - if (options == null) { - options = new MatchRuleDescriptor(topDeclaringType); - map.put(topDeclaringType, options); - } - MatchRule[] matchRules = element.getAnnotationsByType(MatchRule.class); - for (MatchRule matchRule : matchRules) { - processMatchRule(element, options, matchRule); + try { + processedMatchRule.add(element); + + // The annotation element type should ensure this is true. + assert element instanceof ExecutableElement; + + TypeElement topDeclaringType = topDeclaringType(element); + MatchRuleDescriptor info = map.get(topDeclaringType); + if (info == null) { + info = new MatchRuleDescriptor(topDeclaringType); + map.put(topDeclaringType, info); + } + for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) { + // System.err.println(matchRule); + processMethodMatchRule((ExecutableElement) element, info, matchRule); + } + } catch (Throwable t) { + reportExceptionThrow(element, t); } } } - private void processMatchRule(Element element, MatchRuleDescriptor info, MatchRule matchRule) { - assert element instanceof TypeElement; - assert element.getKind() == ElementKind.CLASS; - TypeElement field = (TypeElement) element; + private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule) { + Types typeUtils = processingEnv.getTypeUtils(); - TypeMirror fieldType = field.asType(); - if (fieldType.getKind() != TypeKind.DECLARED) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + MatchRule.class.getName(), element); + if (!method.getModifiers().contains(Modifier.PUBLIC)) { + String msg = String.format("MatchRule method %s must be public", method.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + if (method.getModifiers().contains(Modifier.STATIC)) { + String msg = String.format("MatchRule method %s must be non-static", method.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); return; } - Element enclosing = element.getEnclosingElement(); - String declaringClass = ""; - String separator = ""; - Set originatingElementsList = info.originatingElements; - originatingElementsList.add(field); - while (enclosing != null) { - if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { - if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { - String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); - processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + try { + TypeMirror returnType = method.getReturnType(); + if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) { + String msg = String.format("MatchRule method return type must be %s", ComplexMatchResult.class.getName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + + String rule = matchRule.value(); + RuleParser parser = new RuleParser(rule); + ArrayList expectedTypes = parser.capturedTypes(); + ArrayList expectedNames = parser.capturedNames(); + List actualParameters = method.getParameters(); + if (expectedTypes.size() + 1 < actualParameters.size()) { + String msg = String.format("Too many arguments for match method %s %s", expectedTypes.size() + 1, actualParameters.size()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + + // Walk through the parameters to the method and see if they exist in the match rule. + // The order doesn't matter but only names mentioned in the rule can be used and they + // must be assignment compatible. + for (VariableElement parameter : actualParameters) { + String name = parameter.getSimpleName().toString(); + int nameIndex = expectedNames.indexOf(name); + if (nameIndex == -1) { + String msg = String.format("Argument \"%s\" isn't captured in the match rule", name); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + TypeMirror type = parameter.asType(); + if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) { + String msg = String.format("Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); return; } - originatingElementsList.add(enclosing); - declaringClass = enclosing.getSimpleName() + separator + declaringClass; - separator = "."; - } else { - assert enclosing.getKind() == ElementKind.PACKAGE; + } + + MethodInvokerItem invoker = invokers.get(method); + if (invoker == null) { + invoker = new MethodInvokerItem(method.getSimpleName().toString(), topDeclaringType(method).getSimpleName().toString(), method.getSimpleName().toString(), actualParameters); + invokers.put(method, invoker); } - enclosing = enclosing.getEnclosingElement(); - } - String rule = matchRule.value(); - try { - ArrayList matches = new RuleParser(rule).generateVariants(); + Element enclosing = method.getEnclosingElement(); + String declaringClass = ""; + String separator = ""; + Set originatingElementsList = info.originatingElements; + originatingElementsList.add(method); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { + String msg = String.format("MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + originatingElementsList.add(enclosing); + declaringClass = enclosing.getSimpleName() + separator + declaringClass; + separator = "."; + } else { + assert enclosing.getKind() == ElementKind.PACKAGE; + } + enclosing = enclosing.getEnclosingElement(); + } + + originatingElementsList.addAll(parser.originatingElements); + + List matches = parser.generateVariants(); for (String match : matches) { - info.options.add(new MatchRuleItem(match, declaringClass, field)); + info.matchRules.add(new MatchRuleItem(match, invoker)); } } catch (RuleParseError e) { - processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), element); + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), method); } } - } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java Fri May 02 02:45:26 2014 +0200 @@ -43,7 +43,7 @@ */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target(ElementType.METHOD) @Repeatable(value = MatchRules.class) public @interface MatchRule { String value(); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Fri May 02 02:45:26 2014 +0200 @@ -22,9 +22,14 @@ */ package com.oracle.graal.compiler.match; +import static com.oracle.graal.compiler.GraalDebugConfig.*; + import java.util.*; +import java.util.Map.Entry; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.*; import com.oracle.graal.nodes.*; public class MatchRuleRegistry { @@ -69,6 +74,18 @@ registry.put(theClass, rules); assert registry.get(theClass) == rules; result = rules; + + if (LogVerbose.getValue()) { + try (Scope s = Debug.scope("MatchComplexExpressions")) { + Debug.log("Match rules for %s", theClass.getSimpleName()); + for (Entry, List> entry : result.entrySet()) { + Debug.log(" For node class: %s", entry.getKey()); + for (MatchStatement statement : entry.getValue()) { + Debug.log(" %s", statement.getPattern()); + } + } + } + } } if (result.size() == 0) { diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java Fri May 02 02:45:26 2014 +0200 @@ -28,7 +28,7 @@ * The repeatable representation of {@link MatchRule}. Should never be used directly. */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target(ElementType.METHOD) public @interface MatchRules { MatchRule[] value(); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Fri May 02 02:45:26 2014 +0200 @@ -22,12 +22,19 @@ */ package com.oracle.graal.compiler.match; +import static com.oracle.graal.compiler.GraalDebugConfig.*; + +import java.lang.reflect.*; import java.util.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.match.MatchPattern.MatchResultCode; import com.oracle.graal.compiler.match.MatchPattern.Result; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; /** @@ -36,20 +43,34 @@ */ public class MatchStatement { + private static final DebugMetric MatchStatementSuccess = Debug.metric("MatchStatementSuccess"); + + /** + * A printable name for this statement. Usually it's just the name of the method doing the + * emission. + */ private final String name; + + /** + * The actual match pattern. + */ private final MatchPattern pattern; - private final Class generatorClass; + + /** + * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission. + */ + private Method generatorMethod; - public MatchStatement(String name, MatchPattern pattern) { + /** + * The name of arguments in the order they are expected to be passed to the generator method. + */ + private String[] arguments; + + public MatchStatement(String name, MatchPattern pattern, Method generator, String[] arguments) { this.name = name; this.pattern = pattern; - this.generatorClass = null; - } - - public MatchStatement(String name, MatchPattern pattern, Class generator) { - this.name = name; - this.pattern = pattern; - this.generatorClass = generator; + this.generatorMethod = generator; + this.arguments = arguments; } /** @@ -61,37 +82,56 @@ * @return true if the statement matched something and set a {@link ComplexMatchResult} to be * evaluated by the NodeLIRBuilder. */ - public boolean generate(NodeLIRBuilder builder, ValueNode node, List nodes) { - MatchContext context = new MatchContext(builder, this, node, nodes); - Result result = pattern.match(node, context); - if (result == Result.OK) { - result = context.validate(); + public boolean generate(NodeLIRBuilder builder, int index, ValueNode node, List nodes) { + assert index == nodes.indexOf(node); + // Check that the basic shape matches + Result result = pattern.matchShape(node, this); + if (result != Result.OK) { + return false; } + // Now ensure that the other safety constraints are matched. + MatchContext context = new MatchContext(builder, this, index, node, nodes); + result = pattern.matchUsage(node, context); if (result == Result.OK) { - MatchGenerator generator = null; try { - generator = generatorClass.newInstance(); - // Transfer values into gen - context.transferState(generator); - ComplexMatchResult value = generator.match(builder); + // Invoke the generator method and set the result if it's non null. + ComplexMatchResult value = (ComplexMatchResult) generatorMethod.invoke(builder, buildArgList(context)); if (value != null) { context.setResult(value); + MatchStatementSuccess.increment(); return true; } - } catch (InstantiationException | IllegalAccessException e) { + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new GraalInternalError(e); } } else { - // This is fairly verbose for normal usage. - // if (result.code != MatchResultCode.WRONG_CLASS) { - // // Don't bother logging if it's just the wrong shape. - // Debug.log("while matching %s|%s %s %s %s", context.getRoot().toString(Verbosity.Id), - // context.getRoot().getClass().getSimpleName(), getName(), result, node.graph()); - // } + if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) { + Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result); + } } return false; } + /** + * @param context + * @return the ValueNodes captured by the match rule in the order expected by the + * generatorMethod + */ + private Object[] buildArgList(MatchContext context) { + Object[] result = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + if ("root".equals(arguments[i])) { + result[i] = context.getRoot(); + } else { + result[i] = context.namedNode(arguments[i]); + if (result[i] == null) { + throw new GraalGraphInternalError("Can't find named node %s", arguments[i]); + } + } + } + return result; + } + public String formatMatch(ValueNode root) { return pattern.formatMatch(root); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java Fri May 02 02:45:26 2014 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.nodes.*; /** - * Describes the properties of a node for use when building a {@link MatchPattern}s. + * Describes the properties of a node for use when building a {@link MatchPattern}. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @@ -39,13 +39,7 @@ * if they were directly on the node being described but that may complicate the annotation * processing. */ - Class value(); - - /** - * The name used in match patterns. Defaults to class.getSimpleName() with the word Node removed - * from the end. - */ - String shortName() default ""; + Class nodeClass(); /** * The number of matchable inputs, which may be less than the real number of inputs. diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java Fri May 02 02:45:26 2014 +0200 @@ -35,7 +35,7 @@ public AMD64DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { super(providers, target, linkage); - registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14}); + registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14}); } @Override diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Fri May 02 02:45:26 2014 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.amd64; -import static com.oracle.graal.hotspot.HotSpotBackend.*; +import static com.oracle.graal.hotspot.HotSpotHostBackend.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Fri May 02 02:45:26 2014 +0200 @@ -312,7 +312,7 @@ MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY); AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null); MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY); - AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null); + AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null); } else { // No need to emit the stubs for entries back into the method since // it has no calls that can cause such "return" entries diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Fri May 02 02:45:26 2014 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.amd64; -import static com.oracle.graal.hotspot.HotSpotBackend.*; +import static com.oracle.graal.hotspot.HotSpotHostBackend.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java Fri May 02 02:45:26 2014 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.asm.amd64.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; @@ -41,7 +42,7 @@ @Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME") final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction { - private final Register thread; + private final Register threadRegister; private final int threadLastJavaSpOffset; private final int threadLastJavaPcOffset; private final int threadLastJavaFpOffset; @@ -49,32 +50,51 @@ @Alive(REG) AllocatableValue senderSp; @Alive(REG) AllocatableValue senderFp; - AMD64HotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc, AllocatableValue senderSp, - AllocatableValue senderFp) { - this.thread = thread; + private final SaveRegistersOp saveRegisterOp; + + AMD64HotSpotEnterUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc, + AllocatableValue senderSp, AllocatableValue senderFp, SaveRegistersOp saveRegisterOp) { + this.threadRegister = threadRegister; this.threadLastJavaSpOffset = threadLastJavaSpOffset; this.threadLastJavaPcOffset = threadLastJavaPcOffset; this.threadLastJavaFpOffset = threadLastJavaFpOffset; this.framePc = framePc; this.senderSp = senderSp; this.senderFp = senderFp; + this.saveRegisterOp = saveRegisterOp; } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - final int totalFrameSize = crb.frameMap.totalFrameSize(); + FrameMap frameMap = crb.frameMap; + RegisterConfig registerConfig = frameMap.registerConfig; + RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap); + Register stackPointerRegister = registerConfig.getFrameRegister(); + final int totalFrameSize = frameMap.totalFrameSize(); + + // Push return address. masm.push(asRegister(framePc)); + + // Push base pointer. masm.push(asRegister(senderFp)); - masm.movq(rbp, rsp); + masm.movq(rbp, stackPointerRegister); /* * Allocate a full sized frame. Since return address and base pointer are already in place * (see above) we allocate two words less. */ - masm.decrementq(rsp, totalFrameSize - 2 * crb.target.wordSize); + masm.decrementq(stackPointerRegister, totalFrameSize - 2 * crb.target.wordSize); + + // Save return registers after moving the frame. + final int stackSlotSize = frameMap.stackSlotSize(); + Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long); + masm.movptr(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize), integerResultRegister); + + Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double); + masm.movdbl(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize), floatResultRegister); // Set up last Java values. - masm.movq(new AMD64Address(thread, threadLastJavaSpOffset), rsp); + masm.movq(new AMD64Address(threadRegister, threadLastJavaSpOffset), stackPointerRegister); /* * Save the PC since it cannot easily be retrieved using the last Java SP after we aligned @@ -82,12 +102,12 @@ * blob. */ masm.leaq(rax, new AMD64Address(rip, 0)); - masm.movq(new AMD64Address(thread, threadLastJavaPcOffset), rax); + masm.movq(new AMD64Address(threadRegister, threadLastJavaPcOffset), rax); // Use BP because the frames look interpreted now. - masm.movq(new AMD64Address(thread, threadLastJavaFpOffset), rbp); + masm.movq(new AMD64Address(threadRegister, threadLastJavaFpOffset), rbp); // Align the stack for the following unpackFrames call. - masm.andq(rsp, -(crb.target.stackAlignment)); + masm.andq(stackPointerRegister, -(crb.target.stackAlignment)); } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java Fri May 02 02:45:26 2014 +0200 @@ -26,10 +26,10 @@ import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.api.meta.Value.*; -import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*; import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*; import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*; +import static com.oracle.graal.hotspot.HotSpotHostBackend.*; import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.*; import static com.oracle.graal.hotspot.replacements.CRC32Substitutions.*; import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.*; @@ -63,7 +63,8 @@ register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION)); register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION)); - link(new AMD64DeoptimizationStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64DeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); + link(new AMD64UncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS))); // When the java.ext.dirs property is modified then the crypto classes might not be found. // If that's the case we ignore the ClassNotFoundException and continue since we cannot diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Fri May 02 02:45:26 2014 +0200 @@ -41,6 +41,7 @@ import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; import com.oracle.graal.hotspot.data.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.nodes.type.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; @@ -189,8 +190,8 @@ super.emitForeignCall(linkage, result, arguments, temps, info); } - public void emitLeaveCurrentStackFrame() { - append(new AMD64HotSpotLeaveCurrentStackFrameOp()); + public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) { + append(new AMD64HotSpotLeaveCurrentStackFrameOp(saveRegisterOp)); } public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { @@ -199,18 +200,18 @@ append(new AMD64HotSpotLeaveDeoptimizedStackFrameOp(frameSizeVariable, initialInfoVariable)); } - public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) { - Register thread = getProviders().getRegisters().getThreadRegister(); + public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) { + Register threadRegister = getProviders().getRegisters().getThreadRegister(); Variable framePcVariable = load(framePc); Variable senderSpVariable = load(senderSp); Variable senderFpVariable = load(senderFp); - append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable, - senderSpVariable, senderFpVariable)); + append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable, + senderSpVariable, senderFpVariable, saveRegisterOp)); } - public void emitLeaveUnpackFramesStackFrame() { - Register thread = getProviders().getRegisters().getThreadRegister(); - append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset())); + public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) { + Register threadRegister = getProviders().getRegisters().getThreadRegister(); + append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), saveRegisterOp)); } /** @@ -321,6 +322,21 @@ return result; } + public Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) { + ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(DeoptimizationFetchUnrollInfoCallNode.FETCH_UNROLL_INFO); + + Register thread = getProviders().getRegisters().getThreadRegister(); + append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread)); + Variable result = super.emitForeignCall(linkage, null, thread.asValue(Kind.Long)); + append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread)); + + Map calleeSaveInfo = ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo(); + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); + + return result; + } + protected AMD64ZapRegistersOp emitZapRegisters(Register[] zappedRegisters, Constant[] zapValues) { AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappedRegisters, zapValues); append(zap); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java Fri May 02 02:45:26 2014 +0200 @@ -24,19 +24,50 @@ import static com.oracle.graal.amd64.AMD64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.asm.*; /** - * Pops the current frame off the stack including the return address. + * Pops the current frame off the stack including the return address and restores the return + * registers stored on the stack. */ @Opcode("LEAVE_CURRENT_STACK_FRAME") final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp { + private final SaveRegistersOp saveRegisterOp; + + public AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) { + this.saveRegisterOp = saveRegisterOp; + } + @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + FrameMap frameMap = crb.frameMap; + RegisterConfig registerConfig = frameMap.registerConfig; + RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap); + Register stackPointer = registerConfig.getFrameRegister(); + + // Restore integer result register. + final int stackSlotSize = frameMap.stackSlotSize(); + Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long); + masm.movptr(integerResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize)); + masm.movptr(rdx, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(rdx) * stackSlotSize)); + + // Restore float result register. + Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double); + masm.movdbl(floatResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize)); + + /* + * All of the register save area will be popped of the stack. Only the return address + * remains. + */ leaveFrameAndRestoreRbp(crb, masm); - masm.addq(rsp, crb.target.arch.getReturnAddressSize()); + + // Remove return address. + masm.addq(stackPointer, crb.target.arch.getReturnAddressSize()); } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java Fri May 02 02:45:26 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,14 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; /** - * Pops the current frame off the stack including the return address. + * Pops a deoptimized stack frame off the stack including the return address. */ @Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME") final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp { @@ -47,9 +48,13 @@ @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - masm.addq(rsp, asRegister(frameSize)); - // Restore the frame pointer before stack bang because if a stack overflow is thrown it - // needs to be pushed (and preserved). + Register stackPointer = crb.frameMap.registerConfig.getFrameRegister(); + masm.addq(stackPointer, asRegister(frameSize)); + + /* + * Restore the frame pointer before stack bang because if a stack overflow is thrown it + * needs to be pushed (and preserved). + */ masm.movq(rbp, asRegister(framePointer)); } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java Fri May 02 02:45:26 2014 +0200 @@ -22,12 +22,12 @@ */ package com.oracle.graal.hotspot.amd64; -import static com.oracle.graal.amd64.AMD64.*; - import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; @@ -38,26 +38,42 @@ @Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME") final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction { - private final Register thread; + private final Register threadRegister; private final int threadLastJavaSpOffset; private final int threadLastJavaPcOffset; private final int threadLastJavaFpOffset; - AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset) { - this.thread = thread; + private final SaveRegistersOp saveRegisterOp; + + AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, SaveRegistersOp saveRegisterOp) { + this.threadRegister = threadRegister; this.threadLastJavaSpOffset = threadLastJavaSpOffset; this.threadLastJavaPcOffset = threadLastJavaPcOffset; this.threadLastJavaFpOffset = threadLastJavaFpOffset; + this.saveRegisterOp = saveRegisterOp; } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + FrameMap frameMap = crb.frameMap; + RegisterConfig registerConfig = frameMap.registerConfig; + RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap); + Register stackPointerRegister = registerConfig.getFrameRegister(); + // Restore stack pointer. - masm.movq(rsp, new AMD64Address(thread, threadLastJavaSpOffset)); + masm.movq(stackPointerRegister, new AMD64Address(threadRegister, threadLastJavaSpOffset)); // Clear last Java frame values. - masm.movslq(new AMD64Address(thread, threadLastJavaSpOffset), 0); - masm.movslq(new AMD64Address(thread, threadLastJavaPcOffset), 0); - masm.movslq(new AMD64Address(thread, threadLastJavaFpOffset), 0); + masm.movslq(new AMD64Address(threadRegister, threadLastJavaSpOffset), 0); + masm.movslq(new AMD64Address(threadRegister, threadLastJavaPcOffset), 0); + masm.movslq(new AMD64Address(threadRegister, threadLastJavaFpOffset), 0); + + // Restore return values. + final int stackSlotSize = frameMap.stackSlotSize(); + Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long); + masm.movptr(integerResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize)); + + Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double); + masm.movdbl(floatResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize)); } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Fri May 02 02:45:26 2014 +0200 @@ -244,39 +244,17 @@ setResult(x, result); } - /** - * Helper class to convert the NodeLIRBuilder into the current subclass. - */ - static abstract class AMD64HotSpotMatchGenerator implements MatchGenerator { - public AMD64HotSpotMatchGenerator() { - } - - public ComplexMatchResult match(NodeLIRBuilder gen) { - return match((AMD64HotSpotNodeLIRBuilder) gen); - } - - abstract public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen); - } - @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))") @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))") @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))") @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))") - public static class IfCompareMemory extends AMD64HotSpotMatchGenerator { - IfNode root; - Access access; - ValueNode value; - CompareNode compare; - - @Override - public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen) { - if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) { - return builder -> { - gen.emitCompareCompressedMemory(root, value, access, compare); - return null; - }; - } - return null; + public ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, ValueNode value, Access access) { + if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) { + return builder -> { + emitCompareCompressedMemory(root, value, access, compare); + return null; + }; } + return null; } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64UncommonTrapStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64UncommonTrapStub.java Fri May 02 02:45:26 2014 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.amd64.AMD64.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; + +final class AMD64UncommonTrapStub extends UncommonTrapStub { + + private RegisterConfig registerConfig; + + public AMD64UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { + super(providers, target, linkage); + Register[] allocatable = new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14}; + registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), allocatable); + } + + @Override + public RegisterConfig getRegisterConfig() { + return registerConfig; + } +} diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Fri May 02 02:45:26 2014 +0200 @@ -281,31 +281,8 @@ return result; } - public void emitLeaveCurrentStackFrame() { - throw GraalInternalError.unimplemented(); - } - - public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { - throw GraalInternalError.unimplemented(); - } - - public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) { - throw GraalInternalError.unimplemented(); - } - - public void emitLeaveUnpackFramesStackFrame() { - throw GraalInternalError.unimplemented(); - } - public SaveRegistersOp emitSaveAllRegisters() { throw GraalInternalError.unimplemented(); } - public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { - throw GraalInternalError.unimplemented(); - } - - public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) { - throw GraalInternalError.unimplemented(); - } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java Fri May 02 02:45:26 2014 +0200 @@ -72,31 +72,8 @@ throw GraalInternalError.unimplemented(); } - public void emitLeaveCurrentStackFrame() { - throw GraalInternalError.unimplemented(); - } - - public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { - throw GraalInternalError.unimplemented(); - } - - public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) { - throw GraalInternalError.unimplemented(); - } - - public void emitLeaveUnpackFramesStackFrame() { - throw GraalInternalError.unimplemented(); - } - public SaveRegistersOp emitSaveAllRegisters() { throw GraalInternalError.unimplemented(); } - public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { - throw GraalInternalError.unimplemented(); - } - - public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) { - throw GraalInternalError.unimplemented(); - } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java Fri May 02 02:45:26 2014 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.sparc; -import static com.oracle.graal.hotspot.HotSpotBackend.*; +import static com.oracle.graal.hotspot.HotSpotHostBackend.*; import com.oracle.graal.asm.sparc.*; import com.oracle.graal.lir.*; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Fri May 02 02:45:26 2014 +0200 @@ -232,7 +232,7 @@ MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY); SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null); MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY); - SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null); + SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null); } else { // No need to emit the stubs for entries back into the method since // it has no calls that can cause such "return" entries diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java Fri May 02 02:45:26 2014 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.sparc; -import static com.oracle.graal.hotspot.HotSpotBackend.*; +import static com.oracle.graal.hotspot.HotSpotHostBackend.*; import static com.oracle.graal.sparc.SPARC.*; import com.oracle.graal.api.code.*; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java Fri May 02 02:45:26 2014 +0200 @@ -24,10 +24,10 @@ import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.api.meta.Value.*; -import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*; import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*; import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*; +import static com.oracle.graal.hotspot.HotSpotHostBackend.*; import static com.oracle.graal.sparc.SPARC.*; import com.oracle.graal.api.code.*; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Fri May 02 02:45:26 2014 +0200 @@ -300,7 +300,7 @@ return emitSaveRegisters(savedRegisters, savedRegisterLocations, false); } - public void emitLeaveCurrentStackFrame() { + public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) { append(new SPARCHotSpotLeaveCurrentStackFrameOp()); } @@ -308,7 +308,7 @@ append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp()); } - public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) { + public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) { Register thread = getProviders().getRegisters().getThreadRegister(); Variable framePcVariable = load(framePc); Variable senderSpVariable = load(senderSp); @@ -316,7 +316,7 @@ append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable)); } - public void emitLeaveUnpackFramesStackFrame() { + public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) { Register thread = getProviders().getRegisters().getThreadRegister(); append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset())); } diff -r b3fbf52f34be -r 5ecbed00da23 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 Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Fri May 02 02:45:26 2014 +0200 @@ -26,6 +26,7 @@ import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.compiler.GraalCompiler.*; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.compiler.common.UnsafeAccess.*; import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*; import static com.oracle.graal.nodes.StructuredGraph.*; import static com.oracle.graal.phases.common.InliningUtil.*; @@ -117,11 +118,23 @@ */ private final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); - public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) { + /** + * The address of the native CompileTask associated with this compilation. If 0L, then this + * compilation is being managed by a Graal compilation queue otherwise its managed by a native + * HotSpot compilation queue. + */ + private final long ctask; + + public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long ctask, boolean blocking) { this.backend = backend; this.method = method; this.entryBCI = entryBCI; - this.id = method.allocateCompileId(entryBCI); + if (ctask == 0L) { + this.id = method.allocateCompileId(entryBCI); + } else { + this.id = unsafe.getInt(ctask + backend.getRuntime().getConfig().compileTaskCompileIdOffset); + } + this.ctask = ctask; this.blocking = blocking; this.taskId = uniqueTaskIds.incrementAndGet(); this.status = new AtomicReference<>(CompilationStatus.Queued); @@ -337,13 +350,17 @@ System.exit(-1); } } finally { + int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes); + if (ctask != 0L) { + unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes); + } if ((config.ciTime || config.ciTimeEach || PrintCompRate.getValue() != 0) && installedCode != null) { - long processedBytes = InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes; + long time = CompilationTime.getCurrentValue() - previousCompilationTime; TimeUnit timeUnit = CompilationTime.getTimeUnit(); long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS); CompilerToVM c2vm = backend.getRuntime().getCompilerToVM(); - c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, (int) processedBytes, time, timeUnitsPerSecond, installedCode); + c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode); } if (clearFromCompilationQueue) { @@ -388,7 +405,7 @@ final HotSpotCodeCacheProvider codeCache = backend.getProviders().getCodeCache(); InstalledCode installedCode = null; try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) { - installedCode = codeCache.installMethod(method, compResult); + installedCode = codeCache.installMethod(method, compResult, ctask); } catch (Throwable e) { throw Debug.handle(e); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Fri May 02 02:45:26 2014 +0200 @@ -317,7 +317,7 @@ class CTWCompilationTask extends CompilationTask { CTWCompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method) { - super(backend, method, INVOCATION_ENTRY_BCI, false); + super(backend, method, INVOCATION_ENTRY_BCI, 0L, false); } /** diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Fri May 02 02:45:26 2014 +0200 @@ -45,11 +45,6 @@ public abstract class HotSpotBackend extends Backend { /** - * Descriptor for {@link DeoptimizationStub}. - */ - public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class); - - /** * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the * {@linkplain HotSpotVMConfig#codeInstallerMarkIdExceptionHandlerEntry exception handler} in a * compiled method. @@ -57,11 +52,6 @@ public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class); /** - * Descriptor for SharedRuntime::deopt_blob()->unpack(). - */ - public static final ForeignCallDescriptor DEOPT_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class); - - /** * Descriptor for SharedRuntime::get_ic_miss_stub(). */ public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java Fri May 02 02:45:26 2014 +0200 @@ -34,11 +34,17 @@ public final HotSpotResolvedJavaMethod method; public final int entryBCI; public final int id; + public final long ctask; public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult) { + this(target, method, compResult, 0L); + } + + public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) { super(target, compResult); this.method = method; this.entryBCI = compResult.getEntryBCI(); this.id = compResult.getId(); + this.ctask = ctask; } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java Fri May 02 02:45:26 2014 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot; -import static com.oracle.graal.hotspot.HotSpotBackend.*; +import static com.oracle.graal.hotspot.HotSpotHostBackend.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.CompilationResult.Call; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Fri May 02 02:45:26 2014 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.nodes.spi.*; /** @@ -39,6 +40,16 @@ public abstract class HotSpotHostBackend extends HotSpotBackend implements HostBackend { /** + * Descriptor for {@link DeoptimizationStub#deoptimizationHandler}. + */ + public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptimizationHandler", void.class); + + /** + * Descriptor for {@link UncommonTrapStub#uncommonTrapHandler}. + */ + public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class); + + /** * This will be 0 if stack banging is disabled. */ protected final int pagesToBang; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Fri May 02 02:45:26 2014 +0200 @@ -24,8 +24,10 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.gen.*; @@ -43,21 +45,87 @@ */ void emitTailcall(Value[] args, Value address); - void emitLeaveCurrentStackFrame(); - - void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo); + void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason); - void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp); - - void emitLeaveUnpackFramesStackFrame(); - + /** + * Emits code for a {@link SaveAllRegistersNode}. + * + * @return a {@link SaveRegistersOp} operation + */ SaveRegistersOp emitSaveAllRegisters(); - void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason); + /** + * Emits code for a {@link LeaveCurrentStackFrameNode}. + * + * @param saveRegisterOp saved registers + */ + default void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) { + throw GraalInternalError.unimplemented(); + } + + /** + * Emits code for a {@link LeaveDeoptimizedStackFrameNode}. + * + * @param frameSize + * @param initialInfo + */ + default void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) { + throw GraalInternalError.unimplemented(); + } + + /** + * Emits code for a {@link EnterUnpackFramesStackFrameNode}. + * + * @param framePc + * @param senderSp + * @param senderFp + * @param saveRegisterOp + */ + default void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) { + throw GraalInternalError.unimplemented(); + } - void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo); + /** + * Emits code for a {@link LeaveUnpackFramesStackFrameNode}. + * + * @param saveRegisterOp + */ + default void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) { + throw GraalInternalError.unimplemented(); + } + + /** + * Emits code for a {@link PushInterpreterFrameNode}. + * + * @param frameSize + * @param framePc + * @param senderSp + * @param initialInfo + */ + default void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { + throw GraalInternalError.unimplemented(); + } - Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp); + /** + * Emits code for a {@link UncommonTrapCallNode}. + * + * @param trapRequest + * @param saveRegisterOp + * @return a {@code Deoptimization::UnrollBlock} pointer + */ + default Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) { + throw GraalInternalError.unimplemented(); + } + + /** + * Emits code for a {@link DeoptimizationFetchUnrollInfoCallNode}. + * + * @param saveRegisterOp + * @return a {@code Deoptimization::UnrollBlock} pointer + */ + default Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) { + throw GraalInternalError.unimplemented(); + } /** * Gets a stack slot for a lock at a given lock nesting depth. diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri May 02 02:45:26 2014 +0200 @@ -170,7 +170,7 @@ String name = annotation.name(); Flags.Flag entry = flags.get(name); if (entry == null) { - if (!isRequired(currentArch, annotation.archs())) { + if (annotation.optional() || !isRequired(currentArch, annotation.archs())) { continue; } throw new IllegalArgumentException("flag not found: " + name); @@ -716,6 +716,7 @@ @HotSpotVMFlag(name = "CIPrintCompilerName") @Stable public boolean printCompilerName; @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining; @HotSpotVMFlag(name = "GraalUseFastLocking") @Stable public boolean useFastLocking; + @HotSpotVMFlag(name = "UseGraalCompilationQueue", optional = true) @Stable public boolean useGraalCompilationQueue; @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable; @HotSpotVMFlag(name = "GPUOffload") @Stable public boolean gpuOffload; @HotSpotVMFlag(name = "TieredCompilation") @Stable public boolean tieredCompilation; @@ -1067,6 +1068,9 @@ @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch; @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes; + @HotSpotVMField(name = "CompileTask::_compile_id", type = "uint", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskCompileIdOffset; + @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset; + /** * Value of Method::extra_stack_entries(). */ @@ -1353,8 +1357,6 @@ return unsafe.getAddress(codeCacheHeap + codeHeapMemoryOffset + virtualSpaceHighBoundaryOffset); } - @Stable public long handleDeoptStub; - @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub; @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub; @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_encryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingEncryptAESCryptStub; diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java Fri May 02 02:45:26 2014 +0200 @@ -36,4 +36,6 @@ * required on all architectures. */ String[] archs() default {}; + + boolean optional() default false; } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Fri May 02 02:45:26 2014 +0200 @@ -33,8 +33,10 @@ /** * Compiles a method to machine code. This method is called from the VM * (VMToCompiler::compileMethod). + * + * @param ctask the CompileTask pointer if this is a request from a HotSpot compiler thread */ - void compileMethod(long metaspaceMethod, int entryBCI, boolean blocking); + void compileMethod(long metaspaceMethod, int entryBCI, long ctask, boolean blocking); void shutdownCompiler() throws Exception; diff -r b3fbf52f34be -r 5ecbed00da23 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 Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Fri May 02 02:45:26 2014 +0200 @@ -192,55 +192,57 @@ } } - // Create compilation queue. - CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() { - public GraalDebugConfig getDebugConfig() { - return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null; - } - }); - compileQueue = new Queue(factory); + if (runtime.getConfig().useGraalCompilationQueue) { + + // Create compilation queue. + CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() { + public GraalDebugConfig getDebugConfig() { + return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null; + } + }); + compileQueue = new Queue(factory); - // Create queue status printing thread. - if (PrintQueue.getValue()) { - Thread t = new Thread() { + // Create queue status printing thread. + if (PrintQueue.getValue()) { + Thread t = new Thread() { - @Override - public void run() { - while (true) { - TTY.println(compileQueue.toString()); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { + @Override + public void run() { + while (true) { + TTY.println(compileQueue.toString()); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } } } - } - }; - t.setDaemon(true); - t.start(); - } - - if (PrintCompRate.getValue() != 0) { - if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) { - throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach"); + }; + t.setDaemon(true); + t.start(); } - Thread t = new Thread() { + + if (PrintCompRate.getValue() != 0) { + if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) { + throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach"); + } + Thread t = new Thread() { - @Override - public void run() { - while (true) { - runtime.getCompilerToVM().printCompilationStatistics(true, false); - runtime.getCompilerToVM().resetCompilationStatistics(); - try { - Thread.sleep(PrintCompRate.getValue()); - } catch (InterruptedException e) { + @Override + public void run() { + while (true) { + runtime.getCompilerToVM().printCompilationStatistics(true, false); + runtime.getCompilerToVM().resetCompilationStatistics(); + try { + Thread.sleep(PrintCompRate.getValue()); + } catch (InterruptedException e) { + } } } - } - }; - t.setDaemon(true); - t.start(); + }; + t.setDaemon(true); + t.start(); + } } - BenchmarkCounters.initialize(runtime.getCompilerToVM()); compilerStartTime = System.nanoTime(); @@ -346,23 +348,24 @@ private void enqueue(Method m) throws Throwable { JavaMethod javaMethod = runtime.getHostProviders().getMetaAccess().lookupJavaMethod(m); assert !((HotSpotResolvedJavaMethod) javaMethod).isAbstract() && !((HotSpotResolvedJavaMethod) javaMethod).isNative() : javaMethod; - compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, false); + compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, 0L, false); } public void shutdownCompiler() throws Exception { - try (Enqueueing enqueueing = new Enqueueing()) { - // We have to use a privileged action here because shutting down the compiler might be - // called from user code which very likely contains unprivileged frames. - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Void run() throws Exception { - if (compileQueue != null) { - compileQueue.shutdown(); + if (runtime.getConfig().useGraalCompilationQueue) { + try (Enqueueing enqueueing = new Enqueueing()) { + // We have to use a privileged action here because shutting down the compiler might + // be called from user code which very likely contains unprivileged frames. + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Void run() throws Exception { + if (compileQueue != null) { + compileQueue.shutdown(); + } + return null; } - return null; - } - }); + }); + } } - printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false); phaseTransition("final"); @@ -537,22 +540,34 @@ } @Override - public void compileMethod(long metaspaceMethod, final int entryBCI, final boolean blocking) { + public void compileMethod(long metaspaceMethod, final int entryBCI, long ctask, final boolean blocking) { final HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod); - // We have to use a privileged action here because compilations are enqueued from user code - // which very likely contains unprivileged frames. - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - compileMethod(method, entryBCI, blocking); - return null; - } - }); + if (ctask != 0L) { + // This is on a VM CompilerThread - no user frames exist + compileMethod(method, entryBCI, ctask, false); + } else { + // We have to use a privileged action here because compilations are + // enqueued from user code which very likely contains unprivileged frames. + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + compileMethod(method, entryBCI, 0L, blocking); + return null; + } + }); + } } /** * Compiles a method to machine code. */ - void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, final boolean blocking) { + void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, long ctask, final boolean blocking) { + if (ctask != 0L) { + HotSpotBackend backend = runtime.getHostBackend(); + CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, false); + task.runCompilation(false); + return; + } + boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI; if (osrCompilation && bootstrapRunning) { // no OSR compilations during bootstrap - the compiler is just too slow at this point, @@ -575,7 +590,7 @@ assert method.isQueuedForCompilation(); HotSpotBackend backend = runtime.getHostBackend(); - CompilationTask task = new CompilationTask(backend, method, entryBCI, block); + CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, block); try { compileQueue.execute(task); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Fri May 02 02:45:26 2014 +0200 @@ -206,12 +206,12 @@ return installedCode; } - public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) { + public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) { if (compResult.getId() == -1) { compResult.setId(method.allocateCompileId(compResult.getEntryBCI())); } HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), true); - runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult), installedCode, method.getSpeculationLog()); + runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult, ctask), installedCode, method.getSpeculationLog()); return logOrDump(installedCode, compResult); } @@ -236,7 +236,7 @@ @Override public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) { HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; - return installMethod(hotspotMethod, compResult); + return installMethod(hotspotMethod, compResult, 0L); } public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) { diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Fri May 02 02:45:26 2014 +0200 @@ -103,7 +103,6 @@ public void initialize(HotSpotProviders providers, HotSpotVMConfig c) { TargetDescription target = providers.getCodeCache().getTarget(); - registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub(), NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java Fri May 02 02:45:26 2014 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.StandardOp.SaveRegistersOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.word.*; + +/** + * A call to the runtime code {@code Deoptimization::fetch_unroll_info}. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}) +public class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi { + + @Input private SaveAllRegistersNode registerSaver; + private final ForeignCallsProvider foreignCalls; + public static final ForeignCallDescriptor FETCH_UNROLL_INFO = new ForeignCallDescriptor("fetchUnrollInfo", Word.class, Word.class); + + public DeoptimizationFetchUnrollInfoCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver) { + super(StampFactory.forKind(Kind.fromJavaClass(FETCH_UNROLL_INFO.getResultType()))); + this.registerSaver = (SaveAllRegistersNode) registerSaver; + this.foreignCalls = foreignCalls; + } + + @Override + public LocationIdentity[] getLocationIdentities() { + return foreignCalls.getKilledLocations(FETCH_UNROLL_INFO); + } + + public SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizationFetchUnrollInfoCall(getSaveRegistersOp()); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Word fetchUnrollInfo(long registerSaver); + + public MemoryCheckpoint asMemoryCheckpoint() { + return null; + } + + public MemoryPhiNode asMemoryPhi() { + return null; + } +} diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java Fri May 02 02:45:26 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; @@ -39,12 +40,18 @@ @Input private ValueNode framePc; @Input private ValueNode senderSp; @Input private ValueNode senderFp; + @Input private SaveAllRegistersNode registerSaver; - public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp) { + public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp, ValueNode registerSaver) { super(StampFactory.forVoid()); this.framePc = framePc; this.senderSp = senderSp; this.senderFp = senderFp; + this.registerSaver = (SaveAllRegistersNode) registerSaver; + } + + private SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); } @Override @@ -52,9 +59,9 @@ Value operandValue = gen.operand(framePc); Value senderSpValue = gen.operand(senderSp); Value senderFpValue = gen.operand(senderFp); - ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue); + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue, getSaveRegistersOp()); } @NodeIntrinsic - public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp); + public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp, long registerSaver); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java Fri May 02 02:45:26 2014 +0200 @@ -25,7 +25,7 @@ import com.oracle.graal.compiler.match.*; import com.oracle.graal.nodes.*; -@MatchableNode(shortName = "Compression", value = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class) +@MatchableNode(nodeClass = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class) public class HotSpotMatchableNodes { public static class CompressionNodeAdapter extends MatchNodeAdapter { @Override diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java Fri May 02 02:45:26 2014 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -33,15 +34,22 @@ */ public class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable { - public LeaveCurrentStackFrameNode() { + @Input private SaveAllRegistersNode registerSaver; + + public LeaveCurrentStackFrameNode(ValueNode registerSaver) { super(StampFactory.forVoid()); + this.registerSaver = (SaveAllRegistersNode) registerSaver; + } + + private SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); } @Override public void generate(NodeLIRBuilderTool gen) { - ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame(); + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame(getSaveRegistersOp()); } @NodeIntrinsic - public static native void leaveCurrentStackFrame(); + public static native void leaveCurrentStackFrame(long registerSaver); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java Fri May 02 02:45:26 2014 +0200 @@ -25,6 +25,7 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -34,15 +35,22 @@ */ public class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable { - public LeaveUnpackFramesStackFrameNode() { + @Input private SaveAllRegistersNode registerSaver; + + public LeaveUnpackFramesStackFrameNode(ValueNode registerSaver) { super(StampFactory.forVoid()); + this.registerSaver = (SaveAllRegistersNode) registerSaver; + } + + private SaveRegistersOp getSaveRegistersOp() { + return registerSaver.getSaveRegistersOp(); } @Override public void generate(NodeLIRBuilderTool gen) { - ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame(); + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame(getSaveRegistersOp()); } @NodeIntrinsic - public static native void leaveUnpackFramesStackFrame(); + public static native void leaveUnpackFramesStackFrame(long registerSaver); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java Fri May 02 02:45:26 2014 +0200 @@ -45,30 +45,35 @@ * * The steps taken by this frame are as follows: * - * - push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all potentially - * live registers (at a pollpoint many registers can be live). + *
  • push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all + * potentially live registers (at a pollpoint many registers can be live). * - * - call the C routine: Deoptimization::fetch_unroll_info (this function returns information about - * the number and size of interpreter frames which are equivalent to the frame which is being + *
  • call the C routine: Deoptimization::fetch_unroll_info (this function returns information + * about the number and size of interpreter frames which are equivalent to the frame which is being * deoptimized) * - * - deallocate the unpack frame, restoring only results values. Other volatile registers will now + *
  • deallocate the unpack frame, restoring only results values. Other volatile registers will now * be captured in the vframeArray as needed. * - * - deallocate the deoptimization frame + *
  • deallocate the deoptimization frame * - * - in a loop using the information returned in the previous step push new interpreter frames (take - * care to propagate the return values through each new frame pushed) + *
  • in a loop using the information returned in the previous step push new interpreter frames + * (take care to propagate the return values through each new frame pushed) * - * - create a dummy "unpack_frame" and save the return values (O0, O1, F0) + *
  • create a dummy "unpack_frame" and save the return values (O0, O1, F0) * - * - call the C routine: Deoptimization::unpack_frames (this function lays out values on the + *
  • call the C routine: Deoptimization::unpack_frames (this function lays out values on the * interpreter frame which was just created) * - * - deallocate the dummy unpack_frame + *
  • deallocate the dummy unpack_frame + * + *
  • ensure that all the return values are correctly set and then do a return to the interpreter + * entry point * - * - ensure that all the return values are correctly set and then do a return to the interpreter - * entry point + *

    + * ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet + * because we change the current stack layout and so the code is very sensitive to register + * allocation. */ public class DeoptimizationStub extends SnippetStub { @@ -97,31 +102,15 @@ } /** - * Uncommon trap. - * - * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This - * routine captures the return values and returns a structure which describes the current frame - * size and the sizes of all replacement frames. The current frame is compiled code and may - * contain many inlined functions, each with their own JVM state. We pop the current frame, then - * push all the new frames. Then we call the C routine unpack_frames() to populate these frames. - * Finally unpack_frames() returns us the new target address. Notice that callee-save registers - * are BLOWN here; they have already been captured in the vframeArray at the time the return PC - * was patched. - * - *

    - * ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet - * because we change the current stack layout and so the code is very sensitive to register - * allocation. + * Deoptimization handler for normal deoptimization + * {@link HotSpotVMConfig#deoptimizationUnpackDeopt}. */ @Snippet - private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) { + private static void deoptimizationHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) { final Word thread = registerAsWord(threadRegister); - long registerSaver = SaveAllRegistersNode.saveAllRegisters(); + final long registerSaver = SaveAllRegistersNode.saveAllRegisters(); - final int actionAndReason = readPendingDeoptimization(thread); - writePendingDeoptimization(thread, -1); - - final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason); + final Word unrollBlock = DeoptimizationFetchUnrollInfoCallNode.fetchUnrollInfo(registerSaver); // Pop all the frames we must move/replace. // @@ -131,7 +120,7 @@ // 3: caller of deoptimizing frame (could be compiled/interpreted). // Pop self-frame. - LeaveCurrentStackFrameNode.leaveCurrentStackFrame(); + LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver); // Load the initial info we should save (e.g. frame pointer). final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset()); @@ -193,13 +182,13 @@ * unknown alignment we need to align it here before calling C++ code. */ final Word senderFp = initialInfo; - EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp); + EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver); - // Pass uncommon trap mode to unpack frames. - final int mode = deoptimizationUnpackUncommonTrap(); + // Pass unpack deopt mode to unpack frames. + final int mode = deoptimizationUnpackDeopt(); unpackFrames(UNPACK_FRAMES, thread, mode); - LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(); + LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver); } /** diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java Fri May 02 02:45:26 2014 +0200 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.hotspot.stubs.StubUtil.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Uncommon trap stub. + * + * This is the entry point for code which is returning to a de-optimized frame. + * + * The steps taken by this frame are as follows: + * + *

  • push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all + * potentially live registers (at a pollpoint many registers can be live). + * + *
  • call the C routine: Deoptimization::fetch_unroll_info (this function returns information + * about the number and size of interpreter frames which are equivalent to the frame which is being + * deoptimized) + * + *
  • deallocate the unpack frame, restoring only results values. Other volatile registers will now + * be captured in the vframeArray as needed. + * + *
  • deallocate the deoptimization frame + * + *
  • in a loop using the information returned in the previous step push new interpreter frames + * (take care to propagate the return values through each new frame pushed) + * + *
  • create a dummy "unpack_frame" and save the return values (O0, O1, F0) + * + *
  • call the C routine: Deoptimization::unpack_frames (this function lays out values on the + * interpreter frame which was just created) + * + *
  • deallocate the dummy unpack_frame + * + *
  • ensure that all the return values are correctly set and then do a return to the interpreter + * entry point + * + *

    + * ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet + * because we change the current stack layout and so the code is very sensitive to register + * allocation. + */ +public class UncommonTrapStub extends SnippetStub { + + private final TargetDescription target; + + public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { + super(providers, target, linkage); + this.target = target; + } + + @Override + public boolean preservesRegisters() { + return false; + } + + @Override + protected Object getConstantParameterValue(int index, String name) { + switch (index) { + case 0: + return providers.getRegisters().getThreadRegister(); + case 1: + return providers.getRegisters().getStackPointerRegister(); + default: + throw GraalInternalError.shouldNotReachHere("unknown parameter " + name + " at index " + index); + } + } + + /** + * Uncommon trap handler. + * + * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This + * routine captures the return values and returns a structure which describes the current frame + * size and the sizes of all replacement frames. The current frame is compiled code and may + * contain many inlined functions, each with their own JVM state. We pop the current frame, then + * push all the new frames. Then we call the C routine unpack_frames() to populate these frames. + * Finally unpack_frames() returns us the new target address. Notice that callee-save registers + * are BLOWN here; they have already been captured in the vframeArray at the time the return PC + * was patched. + */ + @Snippet + private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) { + final Word thread = registerAsWord(threadRegister); + final long registerSaver = SaveAllRegistersNode.saveAllRegisters(); + + final int actionAndReason = readPendingDeoptimization(thread); + writePendingDeoptimization(thread, -1); + + final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason); + + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame + // 2: deoptimizing frame + // 3: caller of deoptimizing frame (could be compiled/interpreted). + + // Pop self-frame. + LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver); + + // Load the initial info we should save (e.g. frame pointer). + final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset()); + + // Pop deoptimized frame. + final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset()); + LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo); + + /* + * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for + * total size of the interpreter frames plus shadow page size. Bang one page at a time + * because large sizes can bang beyond yellow and red zones. + * + * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository. + */ + final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset()); + final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages(); + Word stackPointer = readRegister(stackPointerRegister); + + for (int i = 1; i < bangPages; i++) { + stackPointer.writeInt((-i * pageSize()) + stackBias(), 0); + } + + // Load number of interpreter frames. + final int numberOfFrames = unrollBlock.readInt(deoptimizationUnrollBlockNumberOfFramesOffset()); + + // Load address of array of frame sizes. + final Word frameSizes = unrollBlock.readWord(deoptimizationUnrollBlockFrameSizesOffset()); + + // Load address of array of frame PCs. + final Word framePcs = unrollBlock.readWord(deoptimizationUnrollBlockFramePcsOffset()); + + /* + * Get the current stack pointer (sender's original SP) before adjustment so that we can + * save it in the skeletal interpreter frame. + */ + Word senderSp = readRegister(stackPointerRegister); + + // Adjust old interpreter frame to make space for new frame's extra Java locals. + final int callerAdjustment = unrollBlock.readInt(deoptimizationUnrollBlockCallerAdjustmentOffset()); + writeRegister(stackPointerRegister, readRegister(stackPointerRegister).subtract(callerAdjustment)); + + for (int i = 0; i < numberOfFrames; i++) { + final Word frameSize = frameSizes.readWord(i * wordSize()); + final Word framePc = framePcs.readWord(i * wordSize()); + + // Push an interpreter frame onto the stack. + PushInterpreterFrameNode.pushInterpreterFrame(frameSize, framePc, senderSp, initialInfo); + + // Get the current stack pointer (sender SP) and pass it to next frame. + senderSp = readRegister(stackPointerRegister); + } + + // Get final return address. + final Word framePc = framePcs.readWord(numberOfFrames * wordSize()); + + /* + * Enter a frame to call out to unpack frames. Since we changed the stack pointer to an + * unknown alignment we need to align it here before calling C++ code. + */ + final Word senderFp = initialInfo; + EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver); + + // Pass uncommon trap mode to unpack frames. + final int mode = deoptimizationUnpackUncommonTrap(); + unpackFrames(UNPACK_FRAMES, thread, mode); + + LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver); + } + + /** + * Reads the value of the passed register as a Word. + */ + private static Word readRegister(Register register) { + return registerAsWord(register, false, false); + } + + /** + * Writes the value of the passed register. + * + * @param value value the register should be set to + */ + private static void writeRegister(Register register, Word value) { + writeRegisterAsWord(register, value); + } + + @Fold + private static int stackShadowPages() { + return config().useStackBanging ? config().stackShadowPages : 0; + } + + /** + * Returns the stack bias for the host architecture. + * + * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository. + * + * @return stack bias + */ + @Deprecated + @Fold + private static int stackBias() { + return config().stackBias; + } + + @Fold + private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() { + return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset; + } + + @Fold + private static int deoptimizationUnrollBlockCallerAdjustmentOffset() { + return config().deoptimizationUnrollBlockCallerAdjustmentOffset; + } + + @Fold + private static int deoptimizationUnrollBlockNumberOfFramesOffset() { + return config().deoptimizationUnrollBlockNumberOfFramesOffset; + } + + @Fold + private static int deoptimizationUnrollBlockTotalFrameSizesOffset() { + return config().deoptimizationUnrollBlockTotalFrameSizesOffset; + } + + @Fold + private static int deoptimizationUnrollBlockFrameSizesOffset() { + return config().deoptimizationUnrollBlockFrameSizesOffset; + } + + @Fold + private static int deoptimizationUnrollBlockFramePcsOffset() { + return config().deoptimizationUnrollBlockFramePcsOffset; + } + + @Fold + private static int deoptimizationUnrollBlockInitialInfoOffset() { + return config().deoptimizationUnrollBlockInitialInfoOffset; + } + + @Fold + private static int deoptimizationUnpackDeopt() { + return config().deoptimizationUnpackDeopt; + } + + @Fold + private static int deoptimizationUnpackUncommonTrap() { + return config().deoptimizationUnpackUncommonTrap; + } + + public static final ForeignCallDescriptor UNPACK_FRAMES = descriptorFor(UncommonTrapStub.class, "unpackFrames"); + + @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) + public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode); +} diff -r b3fbf52f34be -r 5ecbed00da23 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 Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Fri May 02 02:45:26 2014 +0200 @@ -497,7 +497,7 @@ break; case IROR: assert asIntReg(src).equals(AMD64.rcx); - masm.roll(asIntReg(dst)); + masm.rorl(asIntReg(dst)); break; case LADD: diff -r b3fbf52f34be -r 5ecbed00da23 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 Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Fri May 02 02:45:26 2014 +0200 @@ -113,6 +113,15 @@ } /** + * Gets the size of a stack slot. + * + * @return stack slot size + */ + public int stackSlotSize() { + return target.wordSize; + } + + /** * Gets the frame size of the compiled frame, not including the size of the * {@link Architecture#getReturnAddressSize() return address slot}. * @@ -208,8 +217,8 @@ * @return the index of the stack slot */ public int indexForStackSlot(StackSlot slot) { - assert offsetForStackSlot(slot) % target.wordSize == 0; - return offsetForStackSlot(slot) / target.wordSize; + assert offsetForStackSlot(slot) % stackSlotSize() == 0; + return offsetForStackSlot(slot) / stackSlotSize(); } /** @@ -259,7 +268,7 @@ * @param kind the {@link PlatformKind} to be stored in the spill slot. * @return the size in bytes */ - protected int spillSlotSize(PlatformKind kind) { + public int spillSlotSize(PlatformKind kind) { return target.getSizeInBytes(kind); } @@ -321,7 +330,7 @@ if (slots == 0) { return null; } - spillSize += (slots * target.wordSize); + spillSize += (slots * stackSlotSize()); if (!objects.isEmpty()) { assert objects.length() <= slots; @@ -329,7 +338,7 @@ for (int slotIndex = 0; slotIndex < slots; slotIndex++) { StackSlot objectSlot = null; if (objects.get(slotIndex)) { - objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * target.wordSize); + objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * stackSlotSize()); objectStackSlots.add(objectSlot); if (outObjectStackSlots != null) { outObjectStackSlots.add(objectSlot); @@ -352,7 +361,7 @@ } public ReferenceMap initReferenceMap(boolean hasRegisters) { - ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / target.wordSize); + ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / stackSlotSize()); for (StackSlot slot : objectStackSlots) { setReference(slot, refMap); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Fri May 02 02:45:26 2014 +0200 @@ -74,6 +74,9 @@ if (stamp() == StampFactory.forNodeIntrinsic()) { return false; } + if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) { + return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp())); + } return updateStamp(stamp().join(object().stamp())); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Fri May 02 02:45:26 2014 +0200 @@ -60,21 +60,30 @@ } @Override - public boolean inferStamp() { - if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) { - return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp())); - } - return updateStamp(object.stamp().join(stamp())); - } - - @Override public Node canonical(CanonicalizerTool tool) { assert getKind() == Kind.Object && object.getKind() == Kind.Object; - if (stamp().equals(object.stamp())) { - return object; - } else { + + ObjectStamp my = (ObjectStamp) stamp(); + ObjectStamp other = (ObjectStamp) object.stamp(); + + if (my.type() == null || other.type() == null) { + return this; + } + if (my.isExactType() && !other.isExactType()) { return this; } + if (my.nonNull() && !other.nonNull()) { + return this; + } + if (!my.type().isAssignableFrom(other.type())) { + return this; + } + /* + * The unsafe cast does not add any new type information, so it can be removed. Note that + * this means that the unsafe cast cannot be used to "drop" type information (in which case + * it must not be canonicalized in any case). + */ + return object; } @Override diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java Fri May 02 02:45:26 2014 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.truffle.nodes.asserts.*; import com.oracle.truffle.api.*; @@ -62,7 +61,7 @@ } Stamp stamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0); ConditionAnchorNode valueAnchorNode = graph().add(new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph())))); - UnsafeCastNode piCast = graph().unique(new UnsafeCastNode(objectArgument, stamp, valueAnchorNode)); + PiNode piCast = graph().unique(new PiNode(objectArgument, stamp, valueAnchorNode)); this.replaceAtUsages(piCast); return valueAnchorNode; } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Fri May 02 02:45:26 2014 +0200 @@ -49,12 +49,12 @@ /** * Gets access to AST instrumentation services. */ - Instrumentation instrumentation(); + Instrumentation getInstrumentation(); /** * Access to information visualization services for the specific language. */ - Visualizer visualizer(); + Visualizer getVisualizer(); /** * Add instrumentation to subsequently constructed Truffle ASTs for the guest language; every diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java Fri May 02 02:45:26 2014 +0200 @@ -44,11 +44,11 @@ return sourceManager; } - public final Instrumentation instrumentation() { + public final Instrumentation getInstrumentation() { return instrumentation; } - public Visualizer visualizer() { + public Visualizer getVisualizer() { return visualizer; } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Fri May 02 02:45:26 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,17 +24,103 @@ */ package com.oracle.truffle.api.instrument; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.impl.*; +import com.oracle.truffle.api.nodes.*; + /** * A receiver of Truffle AST {@link ExecutionEvents}, propagated from a {@link Probe} to which the - * instrument is attached. + * instrument is attached, for the benefit of associated tools. *

    - * Disclaimer: experimental interface under development. + * Guidelines for implementing Instruments, with particular attention to avoiding undesired runtime + * performance overhead: + *

      + *
    1. Extend {@link Instrument} and override only the event handling methods for which some action + * is needed.
    2. + *
    3. Instruments are Truffle {@link Node}s and should be coded as much as possible in the desired + * Truffle style, documented more thoroughly elsewhere.
    4. + *
    5. Maintain as little state as possible.
    6. + *
    7. If state is necessary, make it {@code final} if possible.
    8. + *
    9. If non-final state is necessary, annotate it as {@link CompilationFinal} and call + * {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.
    10. + *
    11. Never store a {@link Frame} value in a field.
    12. + *
    13. Minimize computation in standard execution paths.
    14. + *
    15. Callbacks to tools should be made via callbacks provided at construction and stored in + * {@code final} fields.
    16. + *
    17. Tool callback methods should usually be annotated as {@link SlowPath} to prevent them from + * being inlined into fast execution paths.
    18. + *
    19. If computation is needed, and if performance is important, then the computation is best + * expressed as a guest language AST and evaluated using standard Truffle mechanisms so that + * standard Truffle optimizations can be applied.
    20. + *
    + *

    + * Guidelines for attachment to a {@link Probe}: + *

      + *
    1. An Instrument instance must only attached to a single {@link Probe}, each of which is + * associated uniquely with a specific syntactic unit of a guest language program, and thus + * (initially) to a specific {@linkplain Node Truffle AST node}.
    2. + *
    3. When the AST containing such a node is copied at runtime, the {@link Probe} will be shared by + * every copy, and so the Instrument will receive events corresponding to the intended syntactic + * unit of code, independent of which AST copy is being executed.
    4. + *
    + * + *

    + * Disclaimer: experimental; under development. + * + * @see Instrumentation + * @see Probe + * @see Instrument + * @see ASTNodeProber */ -public interface Instrument extends ExecutionEvents { +public class Instrument extends InstrumentationNode { + + protected Instrument() { + } + + public void enter(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, (Object) result); + } - /** - * @return the {@link Probe} to which this instrument is attached. - */ - Probe getProbe(); + public void leave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, Object result) { + } + + public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + } } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Fri May 02 02:45:26 2014 +0200 @@ -24,10 +24,18 @@ */ package com.oracle.truffle.api.instrument; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; /** - * Visualization services for guest language and Truffle information. + * Visualization services for the benefit of {@link Instrumentation}-based tools, possibly + * specialized for each guest language and possibly specialized for relevant information from the + * underlying Truffle implementation. + *

    + * Disclaimer: experimental interface under development. + * + * @See Instrumentation */ public interface Visualizer { @@ -38,6 +46,21 @@ ASTPrinter getASTPrinter(); /** + * A short description of a source location in terms of source + line number. + */ + String displaySourceLocation(Node node); + + /** + * Describes the name of the method containing a node. + */ + String displayMethodName(Node node); + + /** + * The name of the method. + */ + String displayCallTargetName(CallTarget callTarget); + + /** * Converts a value in the guest language to a display string. */ String displayValue(Object value); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrument.java Wed Apr 30 13:40:36 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument.impl; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * An {@link Instrument} that implements all {@link ExecutionEvents} notifications with empty - * methods. - */ -public class DefaultInstrument extends InstrumentationNodeImpl implements Instrument { - - protected DefaultInstrument() { - } - - public void enter(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, byte result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, short result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, long result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, char result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, float result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, Object result) { - } - - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - } - -} diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Fri May 02 02:45:26 2014 +0200 @@ -24,8 +24,12 @@ */ package com.oracle.truffle.api.instrument.impl; +import java.io.*; + +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; public class DefaultVisualizer implements Visualizer { @@ -39,6 +43,43 @@ return astPrinter; } + public String displaySourceLocation(Node node) { + if (node == null) { + return ""; + } + SourceSection section = node.getSourceSection(); + boolean estimated = false; + if (section == null) { + section = node.getEncapsulatingSourceSection(); + estimated = true; + } + + String sourceString; + if (section == null || section.getSource() == null) { + sourceString = ""; + } else { + String sourceName = new File(section.getSource().getName()).getName(); + int startLine = section.getStartLine(); + sourceString = String.format("%s:%d%s", sourceName, startLine, estimated ? "~" : ""); + } + return sourceString; + } + + public String displayMethodName(Node node) { + if (node == null) { + return null; + } + RootNode root = node.getRootNode(); + if (root == null) { + return "unknown"; + } + return root.getCallTarget().toString(); + } + + public String displayCallTargetName(CallTarget callTarget) { + return callTarget.toString(); + } + public String displayValue(Object value) { return value.toString(); } diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java Fri May 02 02:45:26 2014 +0200 @@ -30,10 +30,6 @@ import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.source.*; -/** - * @author mlvdv - * - */ public final class InstrumentationImpl implements Instrumentation { private final ExecutionContext context; @@ -80,7 +76,7 @@ if (probe != null) { return probe; } - probe = InstrumentationNodeImpl.createProbe(this, sourceSection, eventListener); + probe = InstrumentationNode.createProbe(this, sourceSection, eventListener); // Register new probe by unique SourceSection srcToProbe.put(sourceSection, probe); diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java Fri May 02 02:45:26 2014 +0200 @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument.impl; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments. + *

    + * Coordinates propagation of Truffle AST {@link ExecutionEvents}. + */ +public abstract class InstrumentationNode extends Node implements ExecutionEvents { + + // TODO (mlvdv) This is a pretty awkward design; it is a priority to revise it. + + /** + * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection} + * extent of guest language source code. + * + * @param eventListener an optional listener for certain instrumentation-related events. + * @return a new probe + */ + static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { + return new ProbeImpl(instrumentation, sourceSection, eventListener); + } + + /** + * Next in chain. + */ + @Child protected InstrumentationNode next; + + protected InstrumentationNode() { + } + + /** + * @return the instance of {@link Probe} to which this instrument is attached. + */ + public Probe getProbe() { + final InstrumentationNode parent = (InstrumentationNode) getParent(); + return parent == null ? null : parent.getProbe(); + } + + /** + * Add a probe to the end of this probe chain. + */ + private void internalAddInstrument(Instrument newInstrument) { + if (next == null) { + this.next = insert(newInstrument); + } else { + next.internalAddInstrument(newInstrument); + } + } + + private void internalRemoveInstrument(Instrument oldInstrument) { + if (next == null) { + throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument); + } else if (next == oldInstrument) { + if (oldInstrument.next == null) { + this.next = null; + } else { + this.next = insert(oldInstrument.next); + oldInstrument.next = null; + } + } else { + next.internalRemoveInstrument(oldInstrument); + } + } + + /** + * Reports to the instance of {@link Probe} holding this instrument that some essential state + * has changed that requires deoptimization. + */ + @CompilerDirectives.SlowPath + protected void notifyProbeChanged(Instrument instrument) { + final ProbeImpl probe = (ProbeImpl) getProbe(); + probe.notifyProbeChanged(instrument); + } + + private void internalEnter(Node astNode, VirtualFrame frame) { + enter(astNode, frame); + if (next != null) { + next.internalEnter(astNode, frame); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame) { + leave(astNode, frame); + if (next != null) { + next.internalLeave(astNode, frame); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, Object result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + leaveExceptional(astNode, frame, null); + if (next != null) { + next.internalLeaveExceptional(astNode, frame, e); + } + } + + /** + * Holder of a chain of {@linkplain InstrumentationNode instruments}: manages the + * {@link Assumption} that none of the instruments have changed since last checked. + *

    + * An instance is intended to be shared by every clone of the AST node with which it is + * originally attached, so it holds no parent pointer. + *

    + * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful + * for instrumentation about its AST location(s). + */ + private static final class ProbeImpl extends InstrumentationNode implements Probe { + + final InstrumentationImpl instrumentation; + + final InstrumentEventListener eventListener; + + @CompilerDirectives.CompilationFinal private Assumption probeUnchanged; + + /** + * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line + * will cause a halt. + */ + @CompilerDirectives.CompilationFinal private boolean stepping; + + /** + * Source information about the AST node to which this instrumentation is attached. + */ + private final SourceSection probedSourceSection; + + private final Set tags = EnumSet.noneOf(PhylumTag.class); + + private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { + this.instrumentation = instrumentation; + this.probedSourceSection = sourceSection; + this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener; + this.probeUnchanged = Truffle.getRuntime().createAssumption(); + this.next = null; + } + + @Override + public Probe getProbe() { + return this; + } + + @Override + protected void notifyProbeChanged(Instrument instrument) { + probeUnchanged.invalidate(); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + public SourceSection getSourceLocation() { + return probedSourceSection; + } + + public void tagAs(PhylumTag tag) { + assert tag != null; + if (!tags.contains(tag)) { + tags.add(tag); + instrumentation.newTagAdded(this, tag); + } + } + + public boolean isTaggedAs(PhylumTag tag) { + assert tag != null; + return tags.contains(tag); + } + + public Set getPhylumTags() { + return tags; + } + + public void setStepping(boolean stepping) { + if (this.stepping != stepping) { + this.stepping = stepping; + probeUnchanged.invalidate(); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + } + + public boolean isStepping() { + return stepping; + } + + @CompilerDirectives.SlowPath + public void addInstrument(Instrument instrument) { + probeUnchanged.invalidate(); + super.internalAddInstrument(instrument); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + @CompilerDirectives.SlowPath + public void removeInstrument(Instrument instrument) { + probeUnchanged.invalidate(); + super.internalRemoveInstrument(instrument); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + public void notifyEnter(Node astNode, VirtualFrame frame) { + if (stepping || next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + if (stepping) { + eventListener.haltedAt(astNode, frame.materialize()); + } + if (next != null) { + next.internalEnter(astNode, frame); + } + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, byte result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, short result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, int result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, long result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, char result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, float result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, double result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, Object result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeaveExceptional(astNode, frame, e); + } + } + + public void enter(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, Object result) { + } + + public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + } + + } + +} diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNodeImpl.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNodeImpl.java Wed Apr 30 13:40:36 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument.impl; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments. - *

    - * Coordinates propagation of Truffle AST {@link ExecutionEvents}. - */ -public abstract class InstrumentationNodeImpl extends Node implements ExecutionEvents { - - // TODO (mlvdv) This is a pretty awkward design. - - /** - * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection} - * extent of guest language source code. - * - * @param eventListener an optional listener for certain instrumentation-related events. - * @return a new probe - */ - static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { - return new ProbeImpl(instrumentation, sourceSection, eventListener); - } - - /** - * Next in chain. - */ - @Child protected InstrumentationNodeImpl next; - - protected InstrumentationNodeImpl() { - } - - /** - * @return the instance of {@link Probe} to which this instrument is attached. - */ - public Probe getProbe() { - final InstrumentationNodeImpl parent = (InstrumentationNodeImpl) getParent(); - return parent == null ? null : parent.getProbe(); - } - - /** - * Add a probe to the end of this probe chain. - */ - void internalAddInstrument(InstrumentationNodeImpl newInstrument) { - if (next == null) { - this.next = insert(newInstrument); - } else { - next.internalAddInstrument(newInstrument); - } - } - - void internalRemoveInstrument(InstrumentationNodeImpl oldInstrument) { - if (next == null) { - throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument); - } else if (next == oldInstrument) { - if (oldInstrument.next == null) { - this.next = null; - } else { - this.next = insert(oldInstrument.next); - oldInstrument.next = null; - } - } else { - next.internalRemoveInstrument(oldInstrument); - } - } - - /** - * Reports to the instance of {@link Probe} holding this instrument that some essential state - * has changed that requires deoptimization. - */ - @CompilerDirectives.SlowPath - protected void notifyProbeChanged(InstrumentationNodeImpl instrument) { - final ProbeImpl probe = (ProbeImpl) getProbe(); - probe.notifyProbeChanged(instrument); - } - - private void internalEnter(Node astNode, VirtualFrame frame) { - enter(astNode, frame); - if (next != null) { - next.internalEnter(astNode, frame); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame) { - leave(astNode, frame); - if (next != null) { - next.internalLeave(astNode, frame); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, byte result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, short result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, long result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, char result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, float result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, Object result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - leaveExceptional(astNode, frame, null); - if (next != null) { - next.internalLeaveExceptional(astNode, frame, e); - } - } - - /** - * Holder of a chain of {@linkplain InstrumentationNodeImpl instruments}: manages the - * {@link Assumption} that none of the instruments have changed since last checked. - *

    - * An instance is intended to be shared by every clone of the AST node with which it is - * originally attached, so it holds no parent pointer. - *

    - * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful - * for instrumentation about its AST location(s). - */ - private static final class ProbeImpl extends InstrumentationNodeImpl implements Probe { - - final InstrumentationImpl instrumentation; - - final InstrumentEventListener eventListener; - - @CompilerDirectives.CompilationFinal private Assumption probeUnchanged; - - /** - * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line - * will cause a halt. - */ - @CompilerDirectives.CompilationFinal private boolean stepping; - - /** - * Source information about the AST node to which this instrumentation is attached. - */ - private final SourceSection probedSourceSection; - - private final Set tags = EnumSet.noneOf(PhylumTag.class); - - private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { - this.instrumentation = instrumentation; - this.probedSourceSection = sourceSection; - this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener; - this.probeUnchanged = Truffle.getRuntime().createAssumption(); - this.next = null; - } - - @Override - public Probe getProbe() { - return this; - } - - @Override - protected void notifyProbeChanged(InstrumentationNodeImpl instrument) { - probeUnchanged.invalidate(); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - - public SourceSection getSourceLocation() { - return probedSourceSection; - } - - public void tagAs(PhylumTag tag) { - assert tag != null; - if (!tags.contains(tag)) { - tags.add(tag); - instrumentation.newTagAdded(this, tag); - } - } - - public boolean isTaggedAs(PhylumTag tag) { - assert tag != null; - return tags.contains(tag); - } - - public Set getPhylumTags() { - return tags; - } - - public void setStepping(boolean stepping) { - if (this.stepping != stepping) { - this.stepping = stepping; - probeUnchanged.invalidate(); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - } - - public boolean isStepping() { - return stepping; - } - - @CompilerDirectives.SlowPath - public void addInstrument(Instrument instrument) { - probeUnchanged.invalidate(); - final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument; - super.internalAddInstrument(instrumentImpl); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - - @CompilerDirectives.SlowPath - public void removeInstrument(Instrument instrument) { - probeUnchanged.invalidate(); - final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument; - super.internalRemoveInstrument(instrumentImpl); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - - public void notifyEnter(Node astNode, VirtualFrame frame) { - if (stepping || next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - if (stepping) { - eventListener.haltedAt(astNode, frame.materialize()); - } - if (next != null) { - next.internalEnter(astNode, frame); - } - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, byte result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, short result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, int result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, long result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, char result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, float result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, double result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, Object result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeaveExceptional(astNode, frame, e); - } - } - - public void enter(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, byte result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, short result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, long result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, char result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, float result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, Object result) { - } - - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - } - - } - -} diff -r b3fbf52f34be -r 5ecbed00da23 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Apr 30 13:40:36 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Fri May 02 02:45:26 2014 +0200 @@ -317,16 +317,16 @@ /** *

          * variant1 $condition != null
    -     * 
    +     *
          * $type $name = defaultValue($type);
          * if ($condition) {
          *     $name = $value;
          * }
    -     * 
    +     *
          * variant2 $condition != null
          * $type $name = $value;
          * 
    - * + * * . */ private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) { @@ -978,9 +978,8 @@ private List createImplicitChildrenAccessors() { NodeData node = getModel().getNode(); - // Map> expectTypes = new HashMap<>(); - @SuppressWarnings("unchecked") - List> expectTypes = Arrays.> asList(new Set[node.getGenericSpecialization().getParameters().size()]); + List> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null); + List> expectTypes = new ArrayList<>(prototype); for (ExecutableTypeData executableType : node.getExecutableTypes()) { for (int i = 0; i < executableType.getEvaluatedCount(); i++) { @@ -998,8 +997,7 @@ } List methods = new ArrayList<>(); - @SuppressWarnings("unchecked") - List> visitedList = Arrays.> asList(new Set[node.getGenericSpecialization().getParameters().size()]); + List> visitedList = new ArrayList<>(prototype); for (SpecializationData spec : node.getSpecializations()) { int signatureIndex = -1; for (ActualParameter param : spec.getParameters()) { diff -r b3fbf52f34be -r 5ecbed00da23 mx/mx_graal.py --- a/mx/mx_graal.py Wed Apr 30 13:40:36 2014 +0200 +++ b/mx/mx_graal.py Fri May 02 02:45:26 2014 +0200 @@ -1261,13 +1261,13 @@ if mx.get_env('JDT'): t = Task('BuildJavaWithEcj') - build(['--no-native', '--jdt-warning-as-error']) + build(['-p', '--no-native', '--jdt-warning-as-error']) tasks.append(t.stop()) _clean('CleanAfterEcjBuild') t = Task('BuildJavaWithJavac') - build(['--no-native', '--force-javac']) + build(['-p', '--no-native', '--force-javac']) tasks.append(t.stop()) t = Task('Checkheaders') diff -r b3fbf52f34be -r 5ecbed00da23 mxtool/mx.py --- a/mxtool/mx.py Wed Apr 30 13:40:36 2014 +0200 +++ b/mxtool/mx.py Fri May 02 02:45:26 2014 +0200 @@ -1553,9 +1553,13 @@ def _init_classpaths(self): myDir = dirname(__file__) + outDir = join(dirname(__file__), '.jdk' + str(self.version)) + if not exists(outDir): + os.makedirs(outDir) javaSource = join(myDir, 'ClasspathDump.java') - subprocess.check_call([self.javac, '-d', myDir, javaSource]) - self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', myDir, 'ClasspathDump']).split('|')] + if not exists(join(outDir, 'ClasspathDump.class')): + subprocess.check_call([self.javac, '-d', outDir, javaSource]) + self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', outDir, 'ClasspathDump']).split('|')] if not self._bootclasspath or not self._extdirs or not self._endorseddirs: warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'") self._bootclasspath = _filter_non_existant_paths(self._bootclasspath) @@ -1790,6 +1794,131 @@ # Builtin commands +def _defaultEcjPath(): + return get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar')) + +class JavaCompileTask: + def __init__(self, args, proj, reason, javafilelist, jdk, outputDir, deps): + self.proj = proj + self.reason = reason + self.javafilelist = javafilelist + self.deps = deps + self.jdk = jdk + self.outputDir = outputDir + self.done = False + self.args = args + + def __str__(self): + return self.proj.name + + def logCompilation(self, compiler): + log('Compiling Java sources for {} with {}... [{}]'.format(self.proj.name, compiler, self.reason)) + + def execute(self): + argfileName = join(self.proj.dir, 'javafilelist.txt') + argfile = open(argfileName, 'wb') + argfile.write('\n'.join(self.javafilelist)) + argfile.close() + + processorArgs = [] + + aps = self.proj.annotation_processors() + if len(aps) > 0: + processorPath = classpath(aps, resolve=True) + genDir = self.proj.source_gen_dir() + if exists(genDir): + shutil.rmtree(genDir) + os.mkdir(genDir) + processorArgs += ['-processorpath', join(processorPath), '-s', genDir] + else: + processorArgs += ['-proc:none'] + + args = self.args + jdk = self.jdk + outputDir = self.outputDir + compliance = str(jdk.javaCompliance) + cp = classpath(self.proj.name, includeSelf=True) + toBeDeleted = [argfileName] + + jdtJar = None + if not args.javac and args.jdt is not None: + if not args.jdt.endswith('.jar'): + abort('Path for Eclipse batch compiler does not look like a jar file: ' + args.jdt) + jdtJar = args.jdt + if not exists(jdtJar): + if os.path.abspath(jdtJar) == os.path.abspath(_defaultEcjPath()) and get_env('JDT', None) is None: + # Silently ignore JDT if default location is used but does not exist + jdtJar = None + else: + abort('Eclipse batch compiler jar does not exist: ' + args.jdt) + + try: + if not jdtJar: + mainJava = java() + if not args.error_prone: + self.logCompilation('javac') + javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] + if jdk.debug_port is not None: + javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)] + javacCmd += processorArgs + javacCmd += ['@' + argfile.name] + + if not args.warnAPI: + javacCmd.append('-XDignore.symbol.file') + run(javacCmd) + else: + self.logCompilation('javac (with error-prone)') + javaArgs = ['-Xmx1g'] + javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] + javacArgs += processorArgs + javacArgs += ['@' + argfile.name] + if not args.warnAPI: + javacArgs.append('-XDignore.symbol.file') + run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs) + else: + self.logCompilation('JDT') + + jdtVmArgs = ['-Xmx1g', '-jar', jdtJar] + + jdtArgs = ['-' + compliance, + '-cp', cp, '-g', '-enableJavadoc', + '-d', outputDir, + '-bootclasspath', jdk.bootclasspath(), + '-endorseddirs', jdk.endorseddirs(), + '-extdirs', jdk.extdirs()] + jdtArgs += processorArgs + + jdtProperties = join(self.proj.dir, '.settings', 'org.eclipse.jdt.core.prefs') + rootJdtProperties = join(self.proj.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs') + if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties): + # Try to fix a missing properties file by running eclipseinit + eclipseinit([], buildProcessorJars=False) + if not exists(jdtProperties): + log('JDT properties file {0} not found'.format(jdtProperties)) + else: + with open(jdtProperties) as fp: + origContent = fp.read() + content = origContent + if args.jdt_warning_as_error: + content = content.replace('=warning', '=error') + if not args.jdt_show_task_tags: + content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore' + if origContent != content: + jdtPropertiesTmp = jdtProperties + '.tmp' + with open(jdtPropertiesTmp, 'w') as fp: + fp.write(content) + toBeDeleted.append(jdtPropertiesTmp) + jdtArgs += ['-properties', jdtPropertiesTmp] + else: + jdtArgs += ['-properties', jdtProperties] + jdtArgs.append('@' + argfile.name) + + run_java(jdtVmArgs + jdtArgs) + finally: + for n in toBeDeleted: + os.remove(n) + self.done = True + def build(args, parser=None): """compile the Java and C sources, linking the latter @@ -1800,11 +1929,10 @@ if not suppliedParser: parser = ArgumentParser(prog='mx build') - defaultEcjPath = get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar')) - parser = parser if parser is not None else ArgumentParser(prog='mx build') parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)') parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output') + parser.add_argument('-p', action='store_true', dest='parallelize', help='parallelizes Java compilation') parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one') parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs') parser.add_argument('--projects', action='store', help='comma separated projects to build (omit to build all projects)') @@ -1815,7 +1943,7 @@ parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings') compilerSelect = parser.add_mutually_exclusive_group() compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='') - compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='') + compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler', default=_defaultEcjPath(), metavar='') compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not') @@ -1824,20 +1952,6 @@ args = parser.parse_args(args) - jdtJar = None - if not args.javac and args.jdt is not None: - if not args.jdt.endswith('.jar'): - abort('Path for Eclipse batch compiler does not look like a jar file: ' + args.jdt) - jdtJar = args.jdt - if not exists(jdtJar): - if os.path.abspath(jdtJar) == os.path.abspath(defaultEcjPath) and get_env('JDT', None) is None: - # Silently ignore JDT if default location is used but does not exist - jdtJar = None - else: - abort('Eclipse batch compiler jar does not exist: ' + args.jdt) - - built = set() - if args.only is not None: # N.B. This build will not include dependencies including annotation processor dependencies sortedProjects = [project(name) for name in args.only.split(',')] @@ -1870,6 +1984,7 @@ shutil.rmtree(join(genDir, f)) return outputDir + tasks = {} for p in sortedProjects: if p.native: if args.native: @@ -1879,7 +1994,6 @@ run([gmake_cmd(), 'clean'], cwd=p.dir) run([gmake_cmd()], cwd=p.dir) - built.add(p.name) continue else: if not args.java: @@ -1893,17 +2007,19 @@ if not jdk: log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, requiredCompliance)) continue - compliance = str(jdk.javaCompliance) outputDir = prepareOutputDirs(p, args.clean) - cp = classpath(p.name, includeSelf=True) sourceDirs = p.source_dirs() buildReason = 'forced build' if args.force else None + taskDeps = [] if not buildReason: - for dep in p.all_deps([], False): - if dep.name in built: - buildReason = dep.name + ' rebuilt' + for dep in p.all_deps([], includeLibs=False, includeAnnotationProcessors=True): + taskDep = tasks.get(dep.name) + if taskDep: + if not buildReason: + buildReason = dep.name + ' rebuilt' + taskDeps.append(taskDep) jasminAvailable = None javafilelist = [] @@ -1959,7 +2075,6 @@ buildReason = 'class file(s) out of date' break - aps = p.annotation_processors() apsOutOfDate = p.update_current_annotation_processors_file() if apsOutOfDate: buildReason = 'annotation processor(s) changed' @@ -1972,99 +2087,86 @@ logv('[no Java sources for {0} - skipping]'.format(p.name)) continue - # Ensure that the output directories are clean - # prepareOutputDirs(p, True) - - built.add(p.name) - - argfileName = join(p.dir, 'javafilelist.txt') - argfile = open(argfileName, 'wb') - argfile.write('\n'.join(javafilelist)) - argfile.close() - - processorArgs = [] - - if len(aps) > 0: - processorPath = classpath(aps, resolve=True) - genDir = p.source_gen_dir() - if exists(genDir): - shutil.rmtree(genDir) - os.mkdir(genDir) - processorArgs += ['-processorpath', join(processorPath), '-s', genDir] + task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, taskDeps) + + if args.parallelize: + # Best to initialize class paths on main process + jdk.bootclasspath() + task.proc = None + tasks[p.name] = task else: - processorArgs += ['-proc:none'] - - toBeDeleted = [argfileName] - try: - - def logCompilation(p, compiler, reason): - log('Compiling Java sources for {} with {}... [{}]'.format(p.name, compiler, reason)) - - if not jdtJar: - mainJava = java() - if not args.error_prone: - logCompilation(p, 'javac', buildReason) - javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] - if jdk.debug_port is not None: - javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)] - javacCmd += processorArgs - javacCmd += ['@' + argfile.name] - - if not args.warnAPI: - javacCmd.append('-XDignore.symbol.file') - run(javacCmd) + task.execute() + + if args.parallelize: + + def joinTasks(tasks): + failed = [] + for t in tasks: + t.proc.join() + if t.proc.exitcode != 0: + failed.append(t) + return failed + + def checkTasks(tasks): + active = [] + for t in tasks: + if t.proc.is_alive(): + active.append(t) + else: + if t.proc.exitcode != 0: + return ([], joinTasks(tasks)) + return (active, []) + + def remainingDepsDepth(task): + if task._d is None: + incompleteDeps = [d for d in task.deps if d.proc is None or d.proc.is_alive()] + if len(incompleteDeps) == 0: + task._d = 0 else: - logCompilation(p, 'javac (with error-prone)', buildReason) - javaArgs = ['-Xmx1g'] - javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()] - javacArgs += processorArgs - javacArgs += ['@' + argfile.name] - if not args.warnAPI: - javacArgs.append('-XDignore.symbol.file') - run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs) - else: - logCompilation(p, 'JDT', buildReason) - - jdtVmArgs = ['-Xmx1g', '-jar', jdtJar] - - jdtArgs = ['-' + compliance, - '-cp', cp, '-g', '-enableJavadoc', - '-d', outputDir, - '-bootclasspath', jdk.bootclasspath(), - '-endorseddirs', jdk.endorseddirs(), - '-extdirs', jdk.extdirs()] - jdtArgs += processorArgs - - - jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs') - rootJdtProperties = join(p.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs') - if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties): - # Try to fix a missing properties file by running eclipseinit - eclipseinit([], buildProcessorJars=False) - if not exists(jdtProperties): - log('JDT properties file {0} not found'.format(jdtProperties)) + task._d = max([remainingDepsDepth(t) for t in incompleteDeps]) + 1 + return task._d + + def sortWorklist(tasks): + for t in tasks: + t._d = None + return sorted(tasks, lambda x, y: remainingDepsDepth(x) - remainingDepsDepth(y)) + + import multiprocessing + cpus = multiprocessing.cpu_count() + worklist = sortWorklist(tasks.values()) + active = [] + while len(worklist) != 0: + while True: + active, failed = checkTasks(active) + if len(failed) != 0: + assert not active, active + break + if len(active) == cpus: + # Sleep for 1 second + time.sleep(1) else: - with open(jdtProperties) as fp: - origContent = fp.read() - content = origContent - if args.jdt_warning_as_error: - content = content.replace('=warning', '=error') - if not args.jdt_show_task_tags: - content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore' - if origContent != content: - jdtPropertiesTmp = jdtProperties + '.tmp' - with open(jdtPropertiesTmp, 'w') as fp: - fp.write(content) - toBeDeleted.append(jdtPropertiesTmp) - jdtArgs += ['-properties', jdtPropertiesTmp] - else: - jdtArgs += ['-properties', jdtProperties] - jdtArgs.append('@' + argfile.name) - - run_java(jdtVmArgs + jdtArgs) - finally: - for n in toBeDeleted: - os.remove(n) + break + + def executeTask(task): + task.execute() + + def depsDone(task): + for d in task.deps: + if d.proc is None or d.proc.exitcode is None: + return False + return True + + for task in worklist: + if depsDone(task): + worklist.remove(task) + task.proc = multiprocessing.Process(target=executeTask, args=(task,)) + task.proc.start() + active.append(task) + if len(active) == cpus: + break + + worklist = sortWorklist(worklist) + joinTasks(active) for dist in _dists.values(): archive(['@' + dist.name]) @@ -2258,7 +2360,7 @@ return [] pnames = [p.name for p in projs] - build(['--projects', ",".join(pnames)]) + build(['--jdt-warning-as-error', '--projects', ",".join(pnames)]) return archive(pnames) def pylint(args): diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/classfile/systemDictionary.cpp Fri May 02 02:45:26 2014 +0200 @@ -216,7 +216,7 @@ // Forwards to resolve_instance_class_or_null Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { - assert(!THREAD->is_Compiler_thread(), + assert(THREAD->can_call_java(), err_msg("can not load classes with compiler thread: class=%s, classloader=%s", class_name->as_C_string(), class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string())); @@ -2347,7 +2347,7 @@ TRAPS) { methodHandle empty; assert(EnableInvokeDynamic, ""); - assert(!THREAD->is_Compiler_thread(), ""); + assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty)); if (false) { // FIXME: Decide if the Java upcall should resolve signatures. @@ -2400,7 +2400,7 @@ if (spe != NULL && spe->method_type() != NULL) { assert(java_lang_invoke_MethodType::is_instance(spe->method_type()), ""); return Handle(THREAD, spe->method_type()); - } else if (THREAD->is_Compiler_thread()) { + } else if (!THREAD->can_call_java()) { warning("SystemDictionary::find_method_handle_type called from compiler thread"); // FIXME return Handle(); // do not attempt from within compiler, unless it was cached } diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri May 02 02:45:26 2014 +0200 @@ -367,7 +367,7 @@ template(compileTheWorld_name, "compileTheWorld") \ template(shutdownCompiler_name, "shutdownCompiler") \ template(compileMethod_name, "compileMethod") \ - template(compileMethod_signature, "(JIZ)V") \ + template(compileMethod_signature, "(JIJZ)V") \ template(setOption_name, "setOption") \ template(setOption_signature, "(Ljava/lang/String;)Z") \ template(finalizeOptions_name, "finalizeOptions") \ diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/compiler/compileBroker.cpp Fri May 02 02:45:26 2014 +0200 @@ -804,7 +804,7 @@ #if defined(COMPILERGRAAL) _compilers[1] = graal; - c2_count = 0; + c2_count = UseGraalCompilationQueue ? 0 : c2_count; #endif // COMPILERGRAAL #ifdef COMPILER2 @@ -1143,22 +1143,24 @@ return; } -#if defined(COMPILERGRAAL) - // In tiered mode we want to only handle highest tier compiles and - // in non-tiered mode the default level should be - // CompLevel_full_optimization which equals CompLevel_highest_tier. - assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level"); - assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition"); - if (comp_level == CompLevel_full_optimization) { - if (!JavaThread::current()->is_graal_compiling()) { - bool blockingCompilation = is_compile_blocking(method, osr_bci); - GraalCompiler::instance()->compile_method(method, osr_bci, blockingCompilation); - } else { - // Can't enqueue this request because there would be no one to service it, so simply return. +#ifdef COMPILERGRAAL + if (UseGraalCompilationQueue) { + // In tiered mode we want to only handle highest tier compiles and + // in non-tiered mode the default level should be + // CompLevel_full_optimization which equals CompLevel_highest_tier. + assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level"); + assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition"); + if (comp_level == CompLevel_full_optimization) { + if (!JavaThread::current()->is_graal_compiling()) { + bool blockingCompilation = is_compile_blocking(method, osr_bci); + GraalCompiler::instance()->compile_method(method, osr_bci, NULL, blockingCompilation); + } else { + // Can't enqueue this request because there would be no one to service it, so simply return. + } + return; } - return; + assert(TieredCompilation, "should only reach here in tiered mode"); } - assert(TieredCompilation, "should only reach here in tiered mode"); #endif // COMPILERGRAAL // Outputs from the following MutexLocker block: @@ -1881,6 +1883,35 @@ tty->print(s.as_string()); } +void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) { + + if (success) { + task->mark_success(); + if (ci_env != NULL) { + task->set_num_inlined_bytecodes(ci_env->num_inlined_bytecodes()); + } + if (_compilation_log != NULL) { + nmethod* code = task->code(); + if (code != NULL) { + _compilation_log->log_nmethod(thread, code); + } + } + } + + // simulate crash during compilation + assert(task->compile_id() != CICrashAt, "just as planned"); + if (event.should_commit()) { + event.set_method(task->method()); + event.set_compileID(task->compile_id()); + event.set_compileLevel(task->comp_level()); + event.set_succeded(task->is_success()); + event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci); + event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); + event.set_inlinedBytes(task->num_inlined_bytecodes()); + event.commit(); + } +} + // ------------------------------------------------------------------ // CompileBroker::invoke_compiler_on_method // @@ -1929,6 +1960,21 @@ push_jni_handle_block(); Method* target_handle = task->method(); int compilable = ciEnv::MethodCompilable; + AbstractCompiler *comp = compiler(task_level); + +#ifdef COMPILERGRAAL + if (comp != NULL && comp->is_graal()) { + assert(!UseGraalCompilationQueue, "should not reach here"); + GraalCompiler* graal = (GraalCompiler*) comp; + + TraceTime t1("compilation", &time); + EventCompilation event; + + graal->compile_method(target_handle, osr_bci, task, false); + + post_compile(thread, task, event, task->code() != NULL, NULL); + } else +#endif // COMPILERGRAAL { int system_dictionary_modification_counter; { @@ -1960,7 +2006,6 @@ TraceTime t1("compilation", &time); EventCompilation event; - AbstractCompiler *comp = compiler(task_level); if (comp == NULL) { ci_env.record_method_not_compilable("no compiler", !TieredCompilation); } else { @@ -1988,28 +2033,9 @@ err_msg_res("COMPILE SKIPPED: %s", ci_env.failure_reason()); task->print_compilation(tty, msg); } - } else { - task->mark_success(); - task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes()); - if (_compilation_log != NULL) { - nmethod* code = task->code(); - if (code != NULL) { - _compilation_log->log_nmethod(thread, code); - } - } } - // simulate crash during compilation - assert(task->compile_id() != CICrashAt, "just as planned"); - if (event.should_commit()) { - event.set_method(target->get_Method()); - event.set_compileID(compile_id); - event.set_compileLevel(task->comp_level()); - event.set_succeded(task->is_success()); - event.set_isOsr(is_osr); - event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); - event.set_inlinedBytes(task->num_inlined_bytecodes()); - event.commit(); - } + + post_compile(thread, task, event, !ci_env.failing(), &ci_env); } pop_jni_handle_block(); diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/compiler/compileBroker.hpp Fri May 02 02:45:26 2014 +0200 @@ -28,6 +28,7 @@ #include "ci/compilerInterface.hpp" #include "compiler/abstractCompiler.hpp" #include "runtime/perfData.hpp" +#include "trace/tracing.hpp" class nmethod; class nmethodLocker; @@ -339,6 +340,7 @@ static void wait_for_completion(CompileTask* task); static void invoke_compiler_on_method(CompileTask* task); + static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env); static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level); static void push_jni_handle_block(); static void pop_jni_handle_block(); diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Fri May 02 02:45:26 2014 +0200 @@ -422,12 +422,13 @@ methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code)); jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code); jint id = HotSpotCompiledNmethod::id(compiled_code); + CompileTask* task = (CompileTask*) (address) HotSpotCompiledNmethod::ctask(compiled_code); if (id == -1) { // Make sure a valid compile_id is associated with every compile id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci); } result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, - GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, id, false, installed_code, speculation_log); + GraalCompiler::instance(), _debug_recorder, _dependencies, task, id, false, installed_code, speculation_log); cb = nm; } diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Fri May 02 02:45:26 2014 +0200 @@ -44,7 +44,10 @@ // Initialization void GraalCompiler::initialize() { - + if (!should_perform_init()) { + return; + } + ThreadToNativeFromVM trans(JavaThread::current()); JavaThread* THREAD = JavaThread::current(); TRACE_graal_1("GraalCompiler::initialize"); @@ -100,7 +103,7 @@ if (UseCompiler) { _external_deopt_i2c_entry = create_external_deopt_i2c(); #ifdef COMPILERGRAAL - bool bootstrap = FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal; + bool bootstrap = UseGraalCompilationQueue && (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal); #else bool bootstrap = false; #endif @@ -172,7 +175,7 @@ return buffer_blob; } -void GraalCompiler::compile_method(methodHandle method, int entry_bci, jboolean blocking) { +void GraalCompiler::compile_method(methodHandle method, int entry_bci, CompileTask* task, jboolean blocking) { GRAAL_EXCEPTION_CONTEXT if (!_initialized) { CompilationPolicy::policy()->delay_compilation(method()); @@ -182,7 +185,7 @@ assert(_initialized, "must already be initialized"); ResourceMark rm; thread->set_is_graal_compiling(true); - VMToCompiler::compileMethod(method(), entry_bci, blocking); + VMToCompiler::compileMethod(method(), entry_bci, (jlong) (address) task, blocking); thread->set_is_graal_compiling(false); } diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalCompiler.hpp --- a/src/share/vm/graal/graalCompiler.hpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalCompiler.hpp Fri May 02 02:45:26 2014 +0200 @@ -60,7 +60,7 @@ // Compilation entry point for methods virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); - void compile_method(methodHandle target, int entry_bci, jboolean blocking); + void compile_method(methodHandle target, int entry_bci, CompileTask* task, jboolean blocking); // Print compilation timers and statistics virtual void print_timers(); diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Fri May 02 02:45:26 2014 +0200 @@ -156,8 +156,6 @@ //------------------------------------------------------------------------------------------------ - set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack()); - set_address("registerFinalizerAddress", SharedRuntime::register_finalizer); set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address); set_address("osrMigrationEndAddress", SharedRuntime::OSR_migration_end); diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalGlobals.hpp Fri May 02 02:45:26 2014 +0200 @@ -52,6 +52,9 @@ COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true, \ "Bootstrap Graal before running Java main method")) \ \ + COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, false, \ + "Use non-native compilation queue for Graal")) \ + \ product(bool, ForceGraalInitialization, false, \ "Force VM to initialize the compiler even if not used") \ \ diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Fri May 02 02:45:26 2014 +0200 @@ -88,6 +88,7 @@ oop_field(HotSpotCompiledNmethod, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;") \ int_field(HotSpotCompiledNmethod, entryBCI) \ int_field(HotSpotCompiledNmethod, id) \ + long_field(HotSpotCompiledNmethod, ctask) \ end_class \ start_class(HotSpotCompiledRuntimeStub) \ oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;") \ diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalVMToCompiler.cpp --- a/src/share/vm/graal/graalVMToCompiler.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalVMToCompiler.cpp Fri May 02 02:45:26 2014 +0200 @@ -111,7 +111,7 @@ check_pending_exception("Error while calling finalizeOptions"); } -void VMToCompiler::compileMethod(Method* method, int entry_bci, jboolean blocking) { +void VMToCompiler::compileMethod(Method* method, int entry_bci, jlong ctask, jboolean blocking) { assert(method != NULL, "just checking"); Thread* THREAD = Thread::current(); JavaValue result(T_VOID); @@ -119,6 +119,7 @@ args.push_oop(instance()); args.push_long((jlong) (address) method); args.push_int(entry_bci); + args.push_long(ctask); args.push_int(blocking); JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, THREAD); check_pending_exception("Error while calling compileMethod"); diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/graal/graalVMToCompiler.hpp --- a/src/share/vm/graal/graalVMToCompiler.hpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/graal/graalVMToCompiler.hpp Fri May 02 02:45:26 2014 +0200 @@ -60,8 +60,8 @@ // public static void HotSpotOptions.finalizeOptions(boolean ciTime); static void finalizeOptions(jboolean ciTime); - // public abstract boolean compileMethod(long vmId, int entry_bci, boolean blocking); - static void compileMethod(Method* method, int entry_bci, jboolean blocking); + // public abstract boolean compileMethod(long metaspaceMethod, int entryBCI, long ctask, boolean blocking); + static void compileMethod(Method* method, int entry_bci, jlong ctask, jboolean blocking); // public abstract void shutdownCompiler(); static void shutdownCompiler(); diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/interpreter/linkResolver.cpp Fri May 02 02:45:26 2014 +0200 @@ -113,7 +113,7 @@ // Note: with several active threads, the must_be_compiled may be true // while can_be_compiled is false; remove assert // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile"); - if (THREAD->is_Compiler_thread()) { + if (!THREAD->can_call_java()) { // don't force compilation, resolve was on behalf of compiler return; } @@ -364,7 +364,7 @@ return; } } else if (iid == vmIntrinsics::_invokeGeneric - && !THREAD->is_Compiler_thread() + && THREAD->can_call_java() && appendix_result_or_null != NULL) { // This is a method with type-checking semantics. // We will ask Java code to spin an adapter method for it. diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/oops/method.cpp Fri May 02 02:45:26 2014 +0200 @@ -1314,7 +1314,7 @@ // These two methods are static since a GC may move the Method bool Method::load_signature_classes(methodHandle m, TRAPS) { - if (THREAD->is_Compiler_thread()) { + if (!THREAD->can_call_java()) { // There is nothing useful this routine can do from within the Compile thread. // Hopefully, the signature contains only well-known classes. // We could scan for this and return true/false, but the caller won't care. diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/prims/jni.cpp Fri May 02 02:45:26 2014 +0200 @@ -5174,15 +5174,19 @@ *(JNIEnv**)penv = thread->jni_environment(); #ifdef GRAAL - // GraalCompiler needs to have been created in compileBroker.cpp - GraalCompiler* graal_compiler = GraalCompiler::instance(); - if (ForceGraalInitialization && graal_compiler == NULL) { - graal_compiler = new GraalCompiler(); - } - if (graal_compiler != NULL) { - graal_compiler->initialize(); + if (COMPILERGRAAL_PRESENT(UseGraalCompilationQueue) NOT_COMPILERGRAAL(true)) { + // GraalCompiler needs to have been created in compileBroker.cpp + GraalCompiler* graal_compiler = GraalCompiler::instance(); + if (ForceGraalInitialization && graal_compiler == NULL) { + graal_compiler = new GraalCompiler(); + } + if (graal_compiler != NULL) { + graal_compiler->initialize(); + } else { + assert(!UseCompiler, "why isn't there any compiler?"); + } } else { - assert(!UseCompiler, "why isn't there any compiler?"); + // Graal is initialized on a CompilerThread } #endif diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Fri May 02 02:45:26 2014 +0200 @@ -359,7 +359,8 @@ #ifdef ASSERT assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub() || - strcmp("Stub", cb->name()) == 0, + strcmp("Stub", cb->name()) == 0 || + strcmp("Stub", cb->name()) == 0, err_msg("unexpected code blob: %s", cb->name())); #endif #else diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/runtime/javaCalls.cpp Fri May 02 02:45:26 2014 +0200 @@ -52,7 +52,7 @@ guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code"); assert(!thread->owns_locks(), "must release all locks when leaving VM"); - guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler"); + guarantee(thread->can_call_java(), "cannot make java calls from the compiler"); _result = result; // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub, @@ -366,7 +366,7 @@ #endif - assert(!thread->is_Compiler_thread(), "cannot compile from the compiler"); + assert(thread->can_call_java(), "cannot compile from the compiler"); if (CompilationPolicy::must_be_compiled(method)) { CompileBroker::compile_method(method, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(), diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/runtime/thread.cpp Fri May 02 02:45:26 2014 +0200 @@ -2253,7 +2253,7 @@ // Do not throw asynchronous exceptions against the compiler thread // (the compiler thread should not be a Java thread -- fix in 1.4.2) - if (is_Compiler_thread()) return; + if (!can_call_java()) return; { // Actually throw the Throwable against the target Thread - however @@ -3311,6 +3311,12 @@ #endif } +#ifdef COMPILERGRAAL +bool CompilerThread::can_call_java() const { + return _compiler != NULL && _compiler->is_graal(); +} +#endif + void CompilerThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) { JavaThread::oops_do(f, cld_f, cf); if (_scanned_nmethod != NULL && cf != NULL) { @@ -4334,7 +4340,7 @@ { MutexLockerEx ml(doLock ? Threads_lock : NULL); ALL_JAVA_THREADS(p) { - if (p->is_Compiler_thread()) continue; + if (!p->can_call_java()) continue; address pending = (address)p->current_pending_monitor(); if (pending == monitor) { // found a match diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/runtime/thread.hpp Fri May 02 02:45:26 2014 +0200 @@ -321,6 +321,9 @@ virtual bool is_Named_thread() const { return false; } virtual bool is_Worker_thread() const { return false; } + // Can this thread make Java upcalls + virtual bool can_call_java() const { return true; } + // Casts virtual WorkerThread* as_Worker_thread() const { return NULL; } @@ -1876,8 +1879,13 @@ CompilerThread(CompileQueue* queue, CompilerCounters* counters); bool is_Compiler_thread() const { return true; } + +#ifdef COMPILERGRAAL + virtual bool can_call_java() const; +#endif + // Hide this compiler thread from external view. - bool is_hidden_from_external_view() const { return true; } + bool is_hidden_from_external_view() const { return !can_call_java(); } void set_compiler(AbstractCompiler* c) { _compiler = c; } AbstractCompiler* compiler() const { return _compiler; } diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/runtime/vmStructs.cpp Fri May 02 02:45:26 2014 +0200 @@ -1307,6 +1307,7 @@ nonstatic_field(CompileTask, _osr_bci, int) \ nonstatic_field(CompileTask, _comp_level, int) \ nonstatic_field(CompileTask, _compile_id, uint) \ + nonstatic_field(CompileTask, _num_inlined_bytecodes, int) \ nonstatic_field(CompileTask, _next, CompileTask*) \ nonstatic_field(CompileTask, _prev, CompileTask*) \ \ diff -r b3fbf52f34be -r 5ecbed00da23 src/share/vm/utilities/exceptions.cpp --- a/src/share/vm/utilities/exceptions.cpp Wed Apr 30 13:40:36 2014 +0200 +++ b/src/share/vm/utilities/exceptions.cpp Fri May 02 02:45:26 2014 +0200 @@ -84,7 +84,7 @@ #endif // ASSERT if (thread->is_VM_thread() - || thread->is_Compiler_thread() ) { + || !thread->can_call_java() ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object thread->set_pending_exception(Universe::vm_exception(), file, line); @@ -107,7 +107,7 @@ } if (thread->is_VM_thread() - || thread->is_Compiler_thread() ) { + || !thread->can_call_java() ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object thread->set_pending_exception(Universe::vm_exception(), file, line);