# HG changeset patch # User Thomas Wuerthinger # Date 1396188513 -7200 # Node ID 000c283d7b715d27abadcce6c4c6e544f0fe67f4 # Parent 1617b1e25d3118dcfcc40225bd9fb1a5c629de91# Parent 1415a62ac8b267f36952e745adfc3ccbef6d15a8 Merge. diff -r 1617b1e25d31 -r 000c283d7b71 .hgtags --- a/.hgtags Wed Mar 19 11:43:57 2014 +0100 +++ b/.hgtags Sun Mar 30 16:08:33 2014 +0200 @@ -408,3 +408,4 @@ 050a626a88951140df874f7b163e304d07b6c296 jdk9-b01 b188446de75bda5fc52d102cddf242c3ef5ecbdf jdk9-b02 b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03 +483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2 diff -r 1617b1e25d31 -r 000c283d7b71 CHANGELOG.md --- a/CHANGELOG.md Wed Mar 19 11:43:57 2014 +0100 +++ b/CHANGELOG.md Sun Mar 30 16:08:33 2014 +0200 @@ -2,24 +2,42 @@ ## `tip` ### Graal -* New methods for querying memory usage of individual objects and object graphs in Graal API (MetaAccessProvider#getMemorySize, MetaUtil#getMemorySizeRecursive). -* New (tested) invariant that equality comparisons for JavaType/JavaMethod/JavaField values use .equals() instead of '=='. +* ... +### Truffle +* ... + +## Version 0.2 +25-Mar-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.2) + +### Graal +* Use HotSpot stubs for certain array copy operations. +* New methods for querying memory usage of individual objects and object graphs in Graal API (`MetaAccessProvider#getMemorySize`, `MetaUtil#getMemorySizeRecursive`). +* Added tiered configuration (C1 + Graal). +* Initial security model for Graal [GRAAL-22](https://bugs.openjdk.java.net/browse/GRAAL-22). +* New (tested) invariant that equality comparisons for `JavaType`/`JavaMethod`/`JavaField` values use `.equals()` instead of `==`. * Made graph caching compilation-local. +* Added AllocSpy tool for analyzing allocation in Graal using the [Java Allocation Instrumenter](https://code.google.com/p/java-allocation-instrumenter/). +* Initial support for memory arithmetic operations on x86 ### Truffle -* New API TruffleRuntime#createCallNode to create call nodes and to give the runtime system control over its implementation. -* New API RootNode#getCachedCallNodes to get a weak set of CallNodes that have registered to call the RootNode. -* New API to split the AST of a call-site context sensitively. CallNode#split, CallNode#isSplittable, CallNode#getSplitCallTarget, CallNode#getCurrentCallTarget, RootNode#isSplittable, RootNode#split. -* New API to inline a call-site into the call-graph. CallNode#isInlinable, CallNode#inline, CallNode#isInlined. -* New API for the runtime environment to register CallTargets as caller to the RootNode. CallNode#registerCallTarget. -* Improved API for counting nodes in Truffle ASTS. NodeUtil#countNodes can be used with a NodeFilter filter Nodes. -* New API to declare the cost of a Node for use in runtime environment specific heuristics. See NodeCost, Node#getCost() and NodeInfo#cost(). -* Removed old API for NodeInfo#Kind and NodeInfo#kind(). As a replacement the new Node cost API can be used. - +* New API `TruffleRuntime#createCallNode` to create call nodes and to give the runtime system control over its implementation. +* New API `RootNode#getCachedCallNodes` to get a weak set of `CallNode`s that have registered to call the `RootNode`. +* New API to split the AST of a call-site context sensitively. `CallNode#split`, `CallNode#isSplittable`, `CallNode#getSplitCallTarget`, `CallNode#getCurrentCallTarget`, `RootNode#isSplittable`, `RootNode#split`. +* New API to inline a call-site into the call-graph. `CallNode#isInlinable`, `CallNode#inline`, `CallNode#isInlined`. +* New API for the runtime environment to register `CallTarget`s as caller to the `RootNode`. `CallNode#registerCallTarget`. +* Improved API for counting nodes in Truffle ASTs. `NodeUtil#countNodes` can be used with a `NodeFilter`. +* New API to declare the cost of a Node for use in runtime environment specific heuristics. See `NodeCost`, `Node#getCost` and `NodeInfo#cost`. +* Removed old API for `NodeInfo#Kind` and `NodeInfo#kind`. As a replacement the new `NodeCost` API can be used. +* Changed `Node#replace` reason parameter type to `CharSequence` (to enable lazy string building) +* Deprecated `Node#adoptChild` and `Node#adoptChild`, no longer needed in node constructor +* New `Node#insert` method for inserting new nodes into the tree (formerly `adoptChild`) +* New `Node#adoptChildren` helper method that adopts all (direct and indirect) children of a node +* New API `Node#atomic` for atomic tree operations +* Made `Node#replace` thread-safe ## Version 0.1 -5-Feb-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/b124e22eb772) +5-Feb-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.1) ### Graal diff -r 1617b1e25d31 -r 000c283d7b71 README.md --- a/README.md Wed Mar 19 11:43:57 2014 +0100 +++ b/README.md Sun Mar 30 16:08:33 2014 +0200 @@ -23,10 +23,11 @@ Compilation with Graal is only done by explicit requests to the Graal API. This is how Truffle uses Graal. -2. The 'graal' configuration is a VM where all compilation is performed - by Graal and no other compilers are built into the VM binary. This - VM will bootstrap Graal itself at startup unless the -XX:-BootstrapGraal - VM option is given. +2. The 'graal' configuration is a VM where normal compilations are performed + by Graal. This VM will bootstrap Graal itself at startup unless the + -XX:-BootstrapGraal. Note that if tiered compilation is enabled, Graal + will be used at the last tier while C1 will be used for the first compiled + tiers. Unless you use the --vm option with the build command, you will be presented with a dialogue to choose one of the above VM configurations for the build @@ -78,5 +79,3 @@ These configurations aim to match as closely as possible the VM(s) included in the OpenJDK binaries one can download. - No newline at end of file - diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java --- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,7 +26,6 @@ import java.util.*; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.util.*; /** * Computes an ordering of the block that can be used by the linear scan register allocator and the @@ -67,11 +66,11 @@ * * @return sorted list of blocks */ - public static > List computeLinearScanOrder(int blockCount, T startBlock, NodesToDoubles nodeProbabilities) { + public static > List computeLinearScanOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) { List order = new ArrayList<>(); BitSet visitedBlocks = new BitSet(blockCount); - PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities); - computeLinearScanOrder(order, worklist, visitedBlocks, nodeProbabilities); + PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities); + computeLinearScanOrder(order, worklist, visitedBlocks, blockProbabilities); assert checkOrder(order, blockCount); return order; } @@ -81,11 +80,11 @@ * * @return sorted list of blocks */ - public static > List computeCodeEmittingOrder(int blockCount, T startBlock, NodesToDoubles nodeProbabilities) { + public static > List computeCodeEmittingOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) { List order = new ArrayList<>(); BitSet visitedBlocks = new BitSet(blockCount); - PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities); - computeCodeEmittingOrder(order, worklist, visitedBlocks, nodeProbabilities); + PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities); + computeCodeEmittingOrder(order, worklist, visitedBlocks, blockProbabilities); assert checkOrder(order, blockCount); return order; } @@ -93,28 +92,28 @@ /** * Iteratively adds paths to the code emission block order. */ - private static > void computeCodeEmittingOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { + private static > void computeCodeEmittingOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) { while (!worklist.isEmpty()) { T nextImportantPath = worklist.poll(); - addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities); + addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities); } } /** * Iteratively adds paths to the linear scan block order. */ - private static > void computeLinearScanOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { + private static > void computeLinearScanOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) { while (!worklist.isEmpty()) { T nextImportantPath = worklist.poll(); - addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities); + addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities); } } /** * Initializes the priority queue used for the work list of blocks and adds the start block. */ - private static > PriorityQueue initializeWorklist(T startBlock, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { - PriorityQueue result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator(nodeProbabilities)); + private static > PriorityQueue initializeWorklist(T startBlock, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) { + PriorityQueue result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator(blockProbabilities)); result.add(startBlock); visitedBlocks.set(startBlock.getId()); return result; @@ -123,10 +122,10 @@ /** * Add a linear path to the linear scan order greedily following the most likely successor. */ - private static > void addPathToLinearScanOrder(T block, List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { + private static > void addPathToLinearScanOrder(T block, List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) { block.setLinearScanNumber(order.size()); order.add(block); - T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, nodeProbabilities); + T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities); enqueueSuccessors(block, worklist, visitedBlocks); if (mostLikelySuccessor != null) { if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) { @@ -135,17 +134,17 @@ double unscheduledSum = 0.0; for (T pred : mostLikelySuccessor.getPredecessors()) { if (pred.getLinearScanNumber() == -1) { - unscheduledSum += nodeProbabilities.get(pred.getBeginNode()); + unscheduledSum += blockProbabilities.get(pred); } } - if (unscheduledSum > nodeProbabilities.get(block.getBeginNode()) / PENALTY_VERSUS_UNSCHEDULED) { + if (unscheduledSum > blockProbabilities.get(block) / PENALTY_VERSUS_UNSCHEDULED) { // Add this merge only after at least one additional predecessor gets scheduled. visitedBlocks.clear(mostLikelySuccessor.getId()); return; } } - addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks, nodeProbabilities); + addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks, blockProbabilities); } } @@ -153,7 +152,7 @@ * Add a linear path to the code emission order greedily following the most likely successor. */ @SuppressWarnings("unchecked") - private static > void addPathToCodeEmittingOrder(T initialBlock, List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { + private static > void addPathToCodeEmittingOrder(T initialBlock, List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) { T block = initialBlock; while (block != null) { // Skip loop headers if there is only a single loop end block to @@ -184,7 +183,7 @@ } } - T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, nodeProbabilities); + T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities); enqueueSuccessors(block, worklist, visitedBlocks); block = mostLikelySuccessor; } @@ -201,12 +200,11 @@ /** * Find the highest likely unvisited successor block of a given block. */ - private static > T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { + private static > T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) { T result = null; for (T successor : block.getSuccessors()) { - assert nodeProbabilities.get(successor.getBeginNode()) >= 0.0 : "Probabilities must be positive"; - if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && - (result == null || nodeProbabilities.get(successor.getBeginNode()) >= nodeProbabilities.get(result.getBeginNode()))) { + assert blockProbabilities.get(successor) >= 0.0 : "Probabilities must be positive"; + if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || blockProbabilities.get(successor) >= blockProbabilities.get(result))) { result = successor; } } @@ -249,9 +247,9 @@ */ private static class BlockOrderComparator> implements Comparator { - private final NodesToDoubles probabilities; + private final BlocksToDoubles probabilities; - public BlockOrderComparator(NodesToDoubles probabilities) { + public BlockOrderComparator(BlocksToDoubles probabilities) { this.probabilities = probabilities; } @@ -264,7 +262,7 @@ } // Blocks with high probability before blocks with low probability. - if (probabilities.get(a.getBeginNode()) > probabilities.get(b.getBeginNode())) { + if (probabilities.get(a) > probabilities.get(b)) { return -1; } else { return 1; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Sun Mar 30 16:08:33 2014 +0200 @@ -160,68 +160,79 @@ public abstract void emit(TargetDescription target, ByteBuffer buffer); } + public abstract static class ConstantData extends Data { + + private final Constant constant; + + protected ConstantData(Constant constant, int alignment) { + super(alignment); + this.constant = constant; + } + + public Constant getConstant() { + return constant; + } + } + /** * Represents a Java primitive value used in a {@link DataPatch}. This implementation uses * {@link Kind#getByteCount()} bytes to encode each value. */ - public static final class PrimitiveData extends Data { - - public final Constant constant; + public static final class PrimitiveData extends ConstantData { public PrimitiveData(Constant constant, int alignment) { - super(alignment); + super(constant, alignment); assert constant.getKind().isPrimitive(); - this.constant = constant; } @Override public int getSize(TargetDescription target) { - return constant.getKind().getByteCount(); + return getConstant().getKind().getByteCount(); } @Override public Kind getKind() { - return constant.getKind(); + return getConstant().getKind(); } @Override public void emit(TargetDescription target, ByteBuffer buffer) { - switch (constant.getKind()) { + switch (getConstant().getKind()) { case Boolean: - buffer.put(constant.asBoolean() ? (byte) 1 : (byte) 0); + buffer.put(getConstant().asBoolean() ? (byte) 1 : (byte) 0); break; case Byte: - buffer.put((byte) constant.asInt()); + buffer.put((byte) getConstant().asInt()); break; case Char: - buffer.putChar((char) constant.asInt()); + buffer.putChar((char) getConstant().asInt()); break; case Short: - buffer.putShort((short) constant.asInt()); + buffer.putShort((short) getConstant().asInt()); break; case Int: - buffer.putInt(constant.asInt()); + buffer.putInt(getConstant().asInt()); break; case Long: - buffer.putLong(constant.asLong()); + buffer.putLong(getConstant().asLong()); break; case Float: - buffer.putFloat(constant.asFloat()); + buffer.putFloat(getConstant().asFloat()); break; case Double: - buffer.putDouble(constant.asDouble()); + buffer.putDouble(getConstant().asDouble()); break; } } @Override public String toString() { - return constant.toString(); + return getConstant().toString(); } @Override public int hashCode() { - return constant.hashCode(); + return getConstant().hashCode(); } @Override @@ -231,7 +242,7 @@ } if (obj instanceof PrimitiveData) { PrimitiveData other = (PrimitiveData) obj; - return constant.equals(other.constant); + return getConstant().equals(other.getConstant()); } else { return false; } @@ -591,7 +602,15 @@ addInfopoint(new Infopoint(codePos, debugInfo, reason)); } - private void addInfopoint(Infopoint infopoint) { + /** + * Records a custom infopoint in the code section. + * + * Compiler implementations can use this method to record non-standard infopoints, which are not + * handled by the dedicated methods like {@link #recordCall}. + * + * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint} + */ + public void addInfopoint(Infopoint infopoint) { // The infopoints list must always be sorted if (!infopoints.isEmpty() && infopoints.get(infopoints.size() - 1).pcOffset >= infopoint.pcOffset) { // This re-sorting should be very rare diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ExternalCompilationResult.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ExternalCompilationResult.java Wed Mar 19 11:43:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2009, 2013, 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.api.code; - -/** - * Represents the output from compiling a method generated by Graal, but executing in a memory and - * computational subsystem outside the Graal host system. - * - * Output may include the compiled machine code, associated data and references, relocation - * information, deoptimization information, as this result is generated from a structure graph on - * the Graal host system. - */ -public class ExternalCompilationResult extends CompilationResult { - - private static final long serialVersionUID = 1L; - - /** - * Address of the point of entry to the external compilation result. - */ - private long entryPoint; - - public ExternalCompilationResult() { - super(); - } - - /** - * Set the address for the point of entry to the external compilation result. - * - * @param addr the address of the entry point - */ - public void setEntryPoint(long addr) { - entryPoint = addr; - } - - /** - * Return the address for the point of entry to the external compilation result. - * - * @return address value - */ - public long getEntryPoint() { - return entryPoint; - } - - /** - * Gets the {@linkplain #getTargetCode() code} in this compilation result as a string. - */ - public String getCodeString() { - return new String(getTargetCode(), 0, getTargetCodeSize()); - } -} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,6 +29,8 @@ void setRegister(int idx, PlatformKind kind); + PlatformKind getRegister(int idx); + void setStackSlot(int offset, PlatformKind kind); boolean hasRegisterRefMap(); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java Sun Mar 30 16:08:33 2014 +0200 @@ -102,4 +102,10 @@ * @return the register playing the role specified by {@code id} */ Register getRegisterForRole(int id); + + /** + * Determines if all {@link #getAllocatableRegisters() allocatable} registers are + * {@link #getCallerSaveRegisters() caller saved}. + */ + boolean areAllAllocatableRegistersCallerSaved(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/KindInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/KindInterface.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014, 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.api.meta; + +public interface KindInterface { + + Kind getKind(); + +} diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Sun Mar 30 16:08:33 2014 +0200 @@ -28,7 +28,7 @@ * Abstract base class for values manipulated by the compiler. All values have a {@linkplain Kind * kind} and are immutable. */ -public abstract class Value implements Serializable { +public abstract class Value implements Serializable, KindInterface { private static final long serialVersionUID = -6909397188697766469L; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Sun Mar 30 16:08:33 2014 +0200 @@ -1213,6 +1213,7 @@ emitByte(0xD0 | encode); } + @Override public final void ensureUniquePC() { nop(); } @@ -1669,6 +1670,13 @@ emitInt(imm32); } + public final void testl(AMD64Address dst, int imm32) { + prefixq(dst); + emitByte(0xF7); + emitOperandHelper(0, dst); + emitInt(imm32); + } + public final void testl(Register dst, Register src) { prefixAndEncode(dst.encoding, src.encoding); emitArith(0x85, 0xC0, dst, src); @@ -2064,6 +2072,13 @@ emitOperandHelper(dst, src); } + public final void cmpq(AMD64Address dst, int imm32) { + prefixq(dst); + emitByte(0x81); + emitOperandHelper(7, dst); + emitInt(imm32); + } + public final void cmpq(Register dst, int imm32) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xF8, dst, imm32); @@ -2410,6 +2425,13 @@ emitOperandHelper(dst, src); } + public final void testq(AMD64Address dst, int imm32) { + prefixq(dst); + emitByte(0xF7); + emitOperandHelper(0, dst); + emitInt(imm32); + } + public final void xorq(Register dst, int imm32) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xF0, dst, imm32); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java --- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java Sun Mar 30 16:08:33 2014 +0200 @@ -47,7 +47,11 @@ @Override public void jmp(Label l) { - emitString("brn " + nameOf(l) + ";"); + emitJumpToLabelName(nameOf(l)); + } + + public void emitJumpToLabelName(String labelName) { + emitString("brn " + labelName + ";"); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java --- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Sun Mar 30 16:08:33 2014 +0200 @@ -20,20 +20,17 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.oracle.graal.asm.hsail; -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; - import static com.oracle.graal.api.code.MemoryBarriers.*; import static com.oracle.graal.api.code.ValueUtil.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hsail.*; import com.oracle.graal.graph.GraalInternalError; import com.amd.okra.OkraUtil; +import java.lang.reflect.Array; /** * This class contains routines to emit HSAIL assembly code. @@ -68,6 +65,11 @@ return null; } + @Override + public final void ensureUniquePC() { + throw GraalInternalError.unimplemented(); + } + public final void undefined(String str) { emitString("undefined operation " + str); } @@ -158,6 +160,10 @@ emitAddrOp("lda_global_u64", dest, addr); } + public final void emitLoadKernelArg(Value dest, String kernArgName, String argTypeStr) { + emitString("ld_kernarg_" + argTypeStr + " " + HSAIL.mapRegister(dest) + ", [" + kernArgName + "];"); + } + public final void emitStore(Kind kind, Value src, HSAILAddress addr) { emitStore(src, addr, getArgTypeFromKind(kind)); } @@ -314,6 +320,12 @@ emitString(prefix + destType + "_" + srcType + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";"); } + public void emitConvert(Value dest, Value src, Kind destKind, Kind srcKind) { + String destType = getArgTypeFromKind(destKind); + String srcType = getArgTypeFromKind(srcKind); + emitConvert(dest, src, destType, srcType); + } + /** * Emits a convert instruction that uses unsigned prefix, regardless of the type of dest and * src. @@ -335,6 +347,7 @@ } else { Constant consrc = asConstant(src); switch (src.getKind()) { + case Boolean: case Int: return Integer.toString(consrc.asInt()); case Float: @@ -416,9 +429,13 @@ // Emit an instruction with two source operands. emitString(String.format("%s %s, %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0]), mapRegOrConstToString(sources[1]))); break; + case 1: + // Emit an instruction with one source operand. + emitString(String.format("%s %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0]))); + break; default: // Emit an instruction with one source operand. - emitString(String.format("%s %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(sources[0]))); + emitString(String.format("%s %s;", instr, HSAIL.mapRegister(dest))); break; } } @@ -518,9 +535,20 @@ * @param newValue the new value that will be written to the memory location if the cmpValue * comparison matches */ - public void emitAtomicCas(AllocatableValue result, HSAILAddress address, AllocatableValue cmpValue, AllocatableValue newValue) { - emitString(String.format("atomic_cas_global_b%d %s, %s, %s, %s;", getArgSize(cmpValue), HSAIL.mapRegister(result), mapAddress(address), HSAIL.mapRegister(cmpValue), - HSAIL.mapRegister(newValue))); + public void emitAtomicCas(AllocatableValue result, HSAILAddress address, Value cmpValue, Value newValue) { + emitString(String.format("atomic_cas_global_b%d %s, %s, %s, %s;", getArgSize(cmpValue), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(cmpValue), + mapRegOrConstToString(newValue))); + } + + /** + * Emits an atomic_add_global instruction. + * + * @param result result operand that gets the original contents of the memory location + * @param address the memory location + * @param deltaValue the amount to add + */ + public void emitAtomicAdd(AllocatableValue result, HSAILAddress address, Value deltaValue) { + emitString(String.format("atomic_add_global_u%d %s, %s, %s;", getArgSize(result), HSAIL.mapRegister(result), mapAddress(address), mapRegOrConstToString(deltaValue))); } /** @@ -532,7 +560,52 @@ emitString(comment); } + public String getDeoptInfoName() { + return "%_deoptInfo"; + } + + public String getDeoptLabelName() { + return "@L_Deopt"; + } + + public void emitWorkItemAbsId(Value dest) { + emitString(String.format("workitemabsid_u32 %s, 0;", HSAIL.mapRegister(dest))); + } + + public void emitCuId(Value dest) { + emitString(String.format("cuid_u32 %s;", HSAIL.mapRegister(dest))); + } + + public void emitLaneId(Value dest) { + emitString(String.format("laneid_u32 %s;", HSAIL.mapRegister(dest))); + } + + public void emitWaveId(Value dest) { + emitString(String.format("waveid_u32 %s;", HSAIL.mapRegister(dest))); + } + + public void emitMaxWaveId(Value dest) { + // emitString(String.format("maxwaveid_u32 %s;", HSAIL.mapRegister(dest))); + int hardCodedMaxWaveId = 36; + emitComment("// Hard-coded maxwaveid=" + hardCodedMaxWaveId + " until it works"); + emitMov(dest, Constant.forInt(hardCodedMaxWaveId)); + } + + public void emitMultiplyByWavesize(Value dest) { + String regName = HSAIL.mapRegister(dest); + emitString(String.format("mul_u%d %s, %s, WAVESIZE;", getArgSize(dest), regName, regName)); + } + + public void emitGetWavesize(Value dest) { + String regName = HSAIL.mapRegister(dest); + emitString(String.format("mov_b%d %s, WAVESIZE;", getArgSize(dest), regName)); + } + + public void emitLoadAcquire(Value dest, HSAILAddress address) { + emitString(String.format("ld_global_acq_u%d %s, %s;", getArgSize(dest), HSAIL.mapRegister(dest), mapAddress(address))); + } + public void emitStoreRelease(Value src, HSAILAddress address) { - emitAddrOp("st_global_rel_u" + getArgSize(src), src, address); + emitString(String.format("st_global_rel_u%d %s, %s;", getArgSize(src), HSAIL.mapRegister(src), mapAddress(address))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java --- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Sun Mar 30 16:08:33 2014 +0200 @@ -696,6 +696,11 @@ } @Override + public final void ensureUniquePC() { + throw GraalInternalError.unimplemented(); + } + + @Override public void jmp(Label l) { String str = nameOf(l); bra(str); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Sun Mar 30 16:08:33 2014 +0200 @@ -74,6 +74,7 @@ return Placeholder; } + @Override public final void ensureUniquePC() { new Nop().emit(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java Sun Mar 30 16:08:33 2014 +0200 @@ -183,4 +183,9 @@ * Returns a target specific placeholder address that can be used for code patching. */ public abstract AbstractAddress getPlaceholder(); + + /** + * Emits a NOP instruction to advance the current PC. + */ + public abstract void ensureUniquePC(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,43 +23,41 @@ package com.oracle.graal.baseline; import static com.oracle.graal.api.code.TypeCheckHints.*; -import static com.oracle.graal.api.meta.DeoptimizationAction.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static com.oracle.graal.phases.GraalOptions.*; import static java.lang.reflect.Modifier.*; -import java.lang.reflect.*; import java.util.*; +import com.oracle.graal.alloc.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.api.meta.ResolvedJavaType.Representation; import com.oracle.graal.bytecode.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.alloc.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; import com.oracle.graal.java.*; -import com.oracle.graal.java.BciBlockMapping.Block; +import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; -import com.oracle.graal.java.GraphBuilderPhase.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.nodes.java.*; /** * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. */ @SuppressWarnings("all") -public class BaselineCompiler { +public class BaselineCompiler implements BytecodeParser { public BaselineCompiler(GraphBuilderConfiguration graphBuilderConfig, MetaAccessProvider metaAccess) { this.graphBuilderConfig = graphBuilderConfig; @@ -73,13 +71,19 @@ private ProfilingInfo profilingInfo; private BytecodeStream stream; // the bytecode stream - private Block currentBlock; + private Backend backend; + private LIRGenerator lirGen; + private LIRFrameStateBuilder frameState; + private LIRGenerationResult lirGenRes; + + private BciBlock currentBlock; private ValueNode methodSynchronizedObject; private ExceptionDispatchBlock unwindBlock; private final GraphBuilderConfiguration graphBuilderConfig; - private Block[] loopHeaders; + private BciBlock[] loopHeaders; + private BytecodeParseHelper parserHelper; /** * Meters the number of actual bytecodes parsed. @@ -90,9 +94,11 @@ return method; } - public LIR generate(ResolvedJavaMethod method, int entryBCI) { + public CompilationResult generate(ResolvedJavaMethod method, int entryBCI, Backend backend, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, + CompilationResultBuilderFactory factory) { this.method = method; this.entryBCI = entryBCI; + this.backend = backend; profilingInfo = method.getProfilingInfo(); assert method.getCode() != null : "method must contain bytecodes: " + method; this.stream = new BytecodeStream(method.getCode()); @@ -100,12 +106,22 @@ unwindBlock = null; methodSynchronizedObject = null; TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); + + frameState = new LIRFrameStateBuilder(method); + parserHelper = new BytecodeParseHelper<>(frameState); + + // build blocks and LIR instructions try { build(); } finally { filter.remove(); } - return null; + + // emitCode + Assumptions assumptions = new Assumptions(OptAssumptions.getValue()); + GraalCompiler.emitCode(backend, assumptions, lirGenRes, compilationResult, installedCodeOwner, factory); + + return compilationResult; } protected void build() { @@ -114,12 +130,19 @@ TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), " ")); } - Indent indent = Debug.logAndIndent("build graph for %s", method); + // Indent indent = Debug.logAndIndent("build graph for %s", method); // compute the block map, setup exception handlers and get the entrypoint(s) BciBlockMapping blockMap = BciBlockMapping.create(method); loopHeaders = blockMap.loopHeaders; + // add predecessors + for (BciBlock block : blockMap.blocks) { + for (BciBlock successor : block.getSuccessors()) { + successor.getPredecessors().add(block); + } + } + if (isSynchronized(method.getModifiers())) { throw GraalInternalError.unimplemented("Handle synchronized methods"); } @@ -131,11 +154,56 @@ throw GraalInternalError.unimplemented("Handle start block as loop header"); } - for (Block block : blockMap.blocks) { - processBlock(block); + // add loops ? how do we add looks when we haven't parsed the bytecode? + + // create the control flow graph + LIRControlFlowGraph cfg = new LIRControlFlowGraph(blockMap.blocks.toArray(new BciBlock[0]), new Loop[0]); + + BlocksToDoubles blockProbabilities = new BlocksToDoubles(blockMap.blocks.size()); + for (BciBlock b : blockMap.blocks) { + blockProbabilities.put(b, 1); } - indent.outdent(); + // create the LIR + List> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.blocks.size(), blockMap.startBlock, blockProbabilities); + List> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.blocks.size(), blockMap.startBlock, blockProbabilities); + LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder); + + FrameMap frameMap = backend.newFrameMap(); + TargetDescription target = backend.getTarget(); + CallingConvention cc = CodeUtil.getCallingConvention(backend.getProviders().getCodeCache(), CallingConvention.Type.JavaCallee, method, false); + this.lirGenRes = backend.newLIRGenerationResult(lir, frameMap, null); + this.lirGen = backend.newLIRGenerator(cc, lirGenRes); + + try (Scope ds = Debug.scope("BackEnd", lir)) { + try (Scope s = Debug.scope("LIRGen", lirGen)) { + + // possibly add all the arguments to slots in the local variable array + + for (BciBlock block : blockMap.blocks) { + + // lirGen.doBlock(block, method, this); + } + // indent.outdent(); + + lirGen.beforeRegisterAllocation(); + Debug.dump(lir, "After LIR generation"); + } catch (Throwable e) { + throw Debug.handle(e); + } + + // try (Scope s = Debug.scope("Allocator", nodeLirGen)) { + try (Scope s = Debug.scope("Allocator")) { + + if (backend.shouldAllocateRegisters()) { + new LinearScan(target, lir, frameMap).allocate(); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } catch (Throwable e) { + throw Debug.handle(e); + } } public BytecodeStream stream() { @@ -147,11 +215,11 @@ } private void loadLocal(int index, Kind kind) { - throw GraalInternalError.unimplemented(); + parserHelper.loadLocal(index, kind); } private void storeLocal(Kind kind, int index) { - throw GraalInternalError.unimplemented(); + parserHelper.storeLocal(kind, index); } /** @@ -250,7 +318,10 @@ } private void genArithmeticOp(Kind result, int opcode) { - throw GraalInternalError.unimplemented(); + Value a = frameState.ipop(); + Value b = frameState.ipop(); + Value r = lirGen.emitAdd(a, b); + frameState.ipush(r); } private void genIntegerDivOp(Kind result, int opcode) { @@ -434,18 +505,18 @@ throw GraalInternalError.unimplemented(); } - private void processBlock(Block block) { - Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader); - currentBlock = block; - iterateBytecodesForBlock(block); - indent.outdent(); + public void processBlock(BciBlock block) { + try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader)) { + currentBlock = block; + iterateBytecodesForBlock(block); + } } private void createExceptionDispatch(ExceptionDispatchBlock block) { throw GraalInternalError.unimplemented(); } - private void iterateBytecodesForBlock(Block block) { + private void iterateBytecodesForBlock(BciBlock block) { int endBCI = stream.endBCI(); @@ -646,12 +717,12 @@ case RET : genRet(stream.readLocalIndex()); break; case TABLESWITCH : genSwitch(new BytecodeTableSwitch(stream(), bci())); break; case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(stream(), bci())); break; -// case IRETURN : genReturn(frameState.ipop()); break; -// case LRETURN : genReturn(frameState.lpop()); break; -// case FRETURN : genReturn(frameState.fpop()); break; -// case DRETURN : genReturn(frameState.dpop()); break; -// case ARETURN : genReturn(frameState.apop()); break; -// case RETURN : genReturn(null); break; + case IRETURN : genReturn(frameState.ipop()); break; + case LRETURN : genReturn(frameState.lpop()); break; + case FRETURN : genReturn(frameState.fpop()); break; + case DRETURN : genReturn(frameState.dpop()); break; + case ARETURN : genReturn(frameState.apop()); break; + case RETURN : genReturn(null); break; case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; @@ -700,11 +771,31 @@ if (!currentBlock.jsrScope.isEmpty()) { sb.append(' ').append(currentBlock.jsrScope); } - Debug.log(sb.toString()); + Debug.log("%s", sb); } } private void genArrayLength() { throw GraalInternalError.unimplemented(); } + + private void genReturn(Value x) { + // frameState.setRethrowException(false); + frameState.clearStack(); + // if (graphBuilderConfig.eagerInfopointMode()) { + // append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci()))); + // } + + // synchronizedEpilogue(FrameState.AFTER_BCI, x); + // if (frameState.lockDepth() != 0) { + // throw new BailoutException("unbalanced monitors"); + // } + + // lirGen.visitReturn(x); + throw GraalInternalError.unimplemented(); + } + + public void setParameter(int i, Variable emitMove) { + frameState.storeLocal(i, emitMove); + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,62 @@ +/* + * 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.baseline; + +import java.util.*; + +import com.oracle.graal.nodes.cfg.*; + +public class LIRBlock extends AbstractBlockBase { + + public LIRBlock(int id) { + this.id = id; + predecessors = Collections.emptyList(); + successors = Collections.emptyList(); + } + + public Loop getLoop() { + // TODO Auto-generated method stub + return null; + } + + public int getLoopDepth() { + // TODO Auto-generated method stub + return 0; + } + + public boolean isLoopEnd() { + // TODO Auto-generated method stub + return false; + } + + public boolean isLoopHeader() { + // TODO Auto-generated method stub + return false; + } + + public boolean isExceptionEntry() { + // TODO Auto-generated method stub + return false; + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 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.baseline; + +import com.oracle.graal.java.BciBlockMapping.BciBlock; +import com.oracle.graal.nodes.cfg.*; + +public class LIRControlFlowGraph implements AbstractControlFlowGraph { + + private BciBlock[] blocks; + private Loop[] loops; + + public LIRControlFlowGraph(BciBlock[] blocks, Loop[] loops) { + this.blocks = blocks; + this.loops = loops; + } + + public BciBlock[] getBlocks() { + return blocks; + } + + public Loop[] getLoops() { + return loops; + } + + public BciBlock getStartBlock() { + if (blocks.length > 0) { + return blocks[0]; + } + return null; + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRFrameStateBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRFrameStateBuilder.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2014, 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.baseline; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.java.*; + +public class LIRFrameStateBuilder extends AbstractFrameStateBuilder { + + private final Value[] locals; + private final Value[] stack; + private Value[] lockedObjects; + + public LIRFrameStateBuilder(ResolvedJavaMethod method) { + super(method); + + this.locals = new Value[method.getMaxLocals()]; + // we always need at least one stack slot (for exceptions) + this.stack = new Value[Math.max(1, method.getMaxStackSize())]; + } + + protected LIRFrameStateBuilder(LIRFrameStateBuilder other) { + super(other); + // TODO Auto-generated constructor stub + locals = other.locals; + stack = other.stack; + lockedObjects = other.lockedObjects; + } + + @Override + public int localsSize() { + return locals.length; + } + + @Override + public Value localAt(int i) { + return locals[i]; + } + + @Override + public Value stackAt(int i) { + return stack[i]; + } + + @Override + public Value loadLocal(int i) { + Value x = locals[i]; + assert !isTwoSlot(x.getKind()) || locals[i + 1] == null; + assert i == 0 || locals[i - 1] == null || !isTwoSlot(locals[i - 1].getKind()); + return x; + } + + @Override + public void storeLocal(int i, Value x) { + assert x == null || x.getKind() != Kind.Void && x.getKind() != Kind.Illegal : "unexpected value: " + x; + locals[i] = x; + if (x != null && isTwoSlot(x.getKind())) { + // if this is a double word, then kill i+1 + locals[i + 1] = null; + } + if (x != null && i > 0) { + Value p = locals[i - 1]; + if (p != null && isTwoSlot(p.getKind())) { + // if there was a double word at i - 1, then kill it + locals[i - 1] = null; + } + } + } + + @Override + public void storeStack(int i, Value x) { + assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; + stack[i] = x; + } + + @Override + public void push(Kind kind, Value x) { + assert x.getKind() != Kind.Void && x.getKind() != Kind.Illegal; + xpush(assertKind(kind, x)); + if (isTwoSlot(kind)) { + xpush(null); + } + } + + @Override + public void xpush(Value x) { + assert x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal); + stack[stackSize++] = x; + } + + @Override + public void ipush(Value x) { + xpush(assertInt(x)); + } + + @Override + public void fpush(Value x) { + xpush(assertFloat(x)); + } + + @Override + public void apush(Value x) { + xpush(assertObject(x)); + } + + @Override + public void lpush(Value x) { + xpush(assertLong(x)); + } + + @Override + public void dpush(Value x) { + xpush(assertDouble(x)); + + } + + @Override + public void pushReturn(Kind kind, Value x) { + if (kind != Kind.Void) { + push(kind.getStackKind(), x); + } + } + + @Override + public Value pop(Kind kind) { + assert kind != Kind.Void; + if (isTwoSlot(kind)) { + xpop(); + } + return assertKind(kind, xpop()); + } + + @Override + public Value xpop() { + Value result = stack[--stackSize]; + return result; + } + + @Override + public Value ipop() { + return assertInt(xpop()); + } + + @Override + public Value fpop() { + return assertFloat(xpop()); + } + + @Override + public Value apop() { + return assertObject(xpop()); + } + + @Override + public Value lpop() { + assertHigh(xpop()); + return assertLong(xpop()); + } + + @Override + public Value dpop() { + assertHigh(xpop()); + return assertDouble(xpop()); + } + + @Override + public Value[] popArguments(int slotSize, int argSize) { + int base = stackSize - slotSize; + Value[] r = new Value[argSize]; + int argIndex = 0; + int stackindex = 0; + while (stackindex < slotSize) { + Value element = stack[base + stackindex]; + assert element != null; + r[argIndex++] = element; + stackindex += stackSlots(element.getKind()); + } + stackSize = base; + return r; + } + + @Override + public Value peek(int argumentNumber) { + int idx = stackSize() - 1; + for (int i = 0; i < argumentNumber; i++) { + if (stackAt(idx) == null) { + idx--; + assert isTwoSlot(stackAt(idx).getKind()); + } + idx--; + } + return stackAt(idx); + } + + private static Value assertKind(Kind kind, Value x) { + assert x != null && x.getKind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind()); + return x; + } + + private static Value assertLong(Value x) { + assert x != null && (x.getKind() == Kind.Long); + return x; + } + + private static Value assertInt(Value x) { + assert x != null && (x.getKind() == Kind.Int); + return x; + } + + private static Value assertFloat(Value x) { + assert x != null && (x.getKind() == Kind.Float); + return x; + } + + private static Value assertObject(Value x) { + assert x != null && (x.getKind() == Kind.Object); + return x; + } + + private static Value assertDouble(Value x) { + assert x != null && (x.getKind() == Kind.Double); + return x; + } + + private static void assertHigh(Value x) { + assert x == null; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -41,6 +41,7 @@ import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryMemory; import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst; import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg; import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack; @@ -48,7 +49,9 @@ import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp; import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp; import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2MemoryOp; import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op; +import com.oracle.graal.lir.amd64.AMD64Compare.CompareMemoryOp; import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; @@ -57,11 +60,13 @@ import com.oracle.graal.lir.amd64.AMD64ControlFlow.ReturnOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; +import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; +import com.oracle.graal.lir.amd64.AMD64Move.ZeroExtendLoadOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; @@ -87,9 +92,9 @@ } } - public AMD64LIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); - lir.setSpillMoveFactory(new AMD64SpillMoveFactory()); + public AMD64LIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); + lirGenRes.getLIR().setSpillMoveFactory(new AMD64SpillMoveFactory()); } @Override @@ -153,6 +158,10 @@ append(createMove(dst, src)); } + public void emitData(AllocatableValue dst, byte[] data) { + append(new LeaDataOp(dst, data)); + } + @Override public AMD64AddressValue emitAddress(Value base, long displacement, Value index, int scale) { AllocatableValue baseRegister; @@ -215,7 +224,7 @@ return new AMD64AddressValue(target().wordKind, baseRegister, indexRegister, scaleEnum, displacementInt); } - protected AMD64AddressValue asAddressValue(Value address) { + public AMD64AddressValue asAddressValue(Value address) { if (address instanceof AMD64AddressValue) { return (AMD64AddressValue) address; } else { @@ -256,13 +265,6 @@ } @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - AllocatableValue targetAddress = AMD64.rax.asValue(); - emitMove(targetAddress, operand(callTarget.computedAddress())); - append(new AMD64Call.IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState)); - } - - @Override public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability)); } @@ -334,10 +336,46 @@ } } + protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue left, Value right, LIRFrameState state) { + assert kind == right.getKind(); + switch (kind) { + case Int: + append(new CompareMemoryOp(ICMP, left, right, state)); + break; + case Long: + append(new CompareMemoryOp(LCMP, left, right, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + protected void emitCompareRegMemoryOp(Kind kind, Value left, AMD64AddressValue right, LIRFrameState state) { + switch (kind) { + case Int: + append(new CompareMemoryOp(ICMP, left, right, state)); + break; + case Long: + append(new CompareMemoryOp(LCMP, left, right, state)); + break; + case Object: + append(new CompareMemoryOp(ACMP, left, right, state)); + break; + case Float: + append(new CompareMemoryOp(FCMP, left, right, state)); + break; + case Double: + append(new CompareMemoryOp(DCMP, left, right, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + /** * This method emits the compare instruction, and may reorder the operands. It returns true if * it did so. - * + * * @param a the left operand of the comparison * @param b the right operand of the comparison * @return true if the left and right operands were switched, false otherwise @@ -360,12 +398,6 @@ } @Override - public void emitNullCheck(ValueNode v, DeoptimizingNode deopt) { - assert v.kind() == Kind.Object : v + " - " + v.stamp() + " @ " + deopt; - append(new AMD64Move.NullCheckOp(load(operand(v)), state(deopt))); - } - - @Override public Variable emitNegate(Value inputVal) { AllocatableValue input = asAllocatable(inputVal); Variable result = newVariable(input.getKind()); @@ -505,31 +537,24 @@ } } - @Override - protected boolean peephole(ValueNode valueNode) { - if ((valueNode instanceof IntegerDivNode) || (valueNode instanceof IntegerRemNode)) { - FixedBinaryNode divRem = (FixedBinaryNode) valueNode; - FixedNode node = divRem.next(); - while (node instanceof FixedWithNextNode) { - FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node; - if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) { - FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode; - if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && operand(otherDivRem) == null) { - Value[] results = emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode); - if (divRem instanceof IntegerDivNode) { - setResult(divRem, results[0]); - setResult(otherDivRem, results[1]); - } else { - setResult(divRem, results[1]); - setResult(otherDivRem, results[0]); - } - return true; - } - } - node = fixedWithNextNode.next(); - } - } - return false; + protected Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { + Variable result = newVariable(a.getKind()); + append(new BinaryMemory(op, kind, result, a, location, state)); + return result; + } + + protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, AMD64AddressValue address, LIRFrameState state) { + Variable result = newVariable(kind); + append(new Unary2MemoryOp(op, result, address, state)); + return result; + } + + protected Value emitZeroExtendMemory(Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) { + // Issue a zero extending load of the proper bit size and set the result to + // the proper kind. + Variable result = newVariable(resultBits == 32 ? Kind.Int : Kind.Long); + append(new ZeroExtendLoadOp(memoryKind, result, address, state)); + return result; } private void emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) { @@ -959,7 +984,7 @@ } @Override - protected void emitReturn(Value input) { + public void emitReturn(Value input) { append(new ReturnOp(input)); } @@ -975,19 +1000,4 @@ append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(target().wordKind), newVariable(key.getPlatformKind()))); } - @Override - public void visitBreakpointNode(BreakpointNode node) { - JavaType[] sig = new JavaType[node.arguments().size()]; - for (int i = 0; i < sig.length; i++) { - sig[i] = node.arguments().get(i).stamp().javaType(getMetaAccess()); - } - - Value[] parameters = visitInvokeArguments(frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false), node.arguments()); - append(new AMD64BreakpointOp(parameters)); - } - - @Override - public void visitInfopointNode(InfopointNode i) { - append(new InfopointOp(stateFor(i.getState()), i.reason)); - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,482 @@ +/* + * 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.compiler.amd64; + +import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; +import static com.oracle.graal.nodes.ConstantNode.*; +import static com.oracle.graal.phases.GraalOptions.*; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class AMD64MemoryPeephole implements MemoryArithmeticLIRLowerer { + protected final AMD64NodeLIRGenerator gen; + protected List deferredNodes; + + protected AMD64MemoryPeephole(AMD64NodeLIRGenerator gen) { + this.gen = gen; + } + + public Value setResult(ValueNode x, Value operand) { + return gen.setResult(x, operand); + } + + @Override + public boolean memoryPeephole(Access access, MemoryArithmeticLIRLowerable operation, List deferred) { + this.deferredNodes = deferred; + boolean result = operation.generate(this, access); + if (result) { + Debug.log("merge %s %s with %1s %s %s", access, access.asNode().stamp(), operation, result, access.asNode().graph().method()); + } else { + Debug.log("can't merge %s %s with %1s", access, access.asNode().stamp(), operation); + } + this.deferredNodes = null; + return result; + } + + protected LIRFrameState getState(Access access) { + if (access instanceof DeoptimizingNode) { + return gen.getLIRGenerator().state((DeoptimizingNode) access); + } + return null; + } + + protected AMD64AddressValue makeAddress(Access access) { + return (AMD64AddressValue) access.nullCheckLocation().generateAddress(gen, gen.operand(access.object())); + } + + protected Value emitBinaryMemory(AMD64Arithmetic op, boolean commutative, ValueNode x, ValueNode y, Access access) { + ValueNode other = x; + if (other == access) { + if (commutative) { + other = y; + } else { + return null; + } + } + ensureEvaluated(other); + return gen.getLIRGenerator().emitBinaryMemory(op, access.nullCheckLocation().getValueKind(), gen.getLIRGeneratorTool().asAllocatable(gen.operand(other)), makeAddress(access), getState(access)); + } + + /** + * Constants with multiple users need to be evaluated in the right location so that later users + * can pick up the operand. Make sure that happens when it needs to. + */ + protected void ensureEvaluated(ValueNode node) { + evaluateDeferred(node); + evaluateDeferred(); + } + + protected void evaluateDeferred(ValueNode node) { + // Ensure the other input value has a generated value. + if (ConstantNodeRecordsUsages) { + if (!gen.hasOperand(node)) { + assert node instanceof ConstantNode : node; + ((ConstantNode) node).generate(gen); + } + } + } + + protected void evaluateDeferred() { + if (deferredNodes != null) { + for (ValueNode node : deferredNodes) { + evaluateDeferred(node); + } + } + } + + protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) { + AMD64AddressValue address = makeAddress(access); + LIRFrameState state = getState(access); + evaluateDeferred(); + return gen.getLIRGenerator().emitConvert2MemoryOp(kind, op, address, state); + } + + @Override + public Value emitAddMemory(ValueNode x, ValueNode y, Access access) { + switch (access.nullCheckLocation().getValueKind()) { + case Int: + return emitBinaryMemory(IADD, true, x, y, access); + case Long: + return emitBinaryMemory(LADD, true, x, y, access); + case Float: + return emitBinaryMemory(FADD, true, x, y, access); + case Double: + return emitBinaryMemory(DADD, true, x, y, access); + default: + return null; + } + } + + @Override + public Value emitSubMemory(ValueNode x, ValueNode y, Access access) { + switch (access.nullCheckLocation().getValueKind()) { + case Int: + return emitBinaryMemory(ISUB, false, x, y, access); + case Long: + return emitBinaryMemory(LSUB, false, x, y, access); + case Float: + return emitBinaryMemory(FSUB, false, x, y, access); + case Double: + return emitBinaryMemory(DSUB, false, x, y, access); + default: + return null; + } + } + + @Override + public Value emitMulMemory(ValueNode x, ValueNode y, Access access) { + switch (access.nullCheckLocation().getValueKind()) { + case Int: + return emitBinaryMemory(IMUL, true, x, y, access); + case Long: + return emitBinaryMemory(LMUL, true, x, y, access); + case Float: + return emitBinaryMemory(FMUL, true, x, y, access); + case Double: + return emitBinaryMemory(DMUL, true, x, y, access); + default: + return null; + } + } + + @Override + public Value emitDivMemory(ValueNode x, ValueNode y, Access access) { + return null; + } + + @Override + public Value emitRemMemory(ValueNode x, ValueNode y, Access access) { + return null; + } + + @Override + public Value emitAndMemory(ValueNode x, ValueNode y, Access access) { + Kind kind = access.nullCheckLocation().getValueKind(); + switch (kind) { + case Int: + return emitBinaryMemory(IAND, true, x, y, access); + case Long: + return emitBinaryMemory(LAND, true, x, y, access); + case Short: { + ValueNode other = x == access ? y : x; + Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null; + if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) { + // Convert to unsigned load + ensureEvaluated(other); + return emitZeroExtendMemory(16, 32, access); + } + return null; + } + case Byte: { + if (OptFoldMemory.getValue()) { + return null; + } + ValueNode other = x == access ? y : x; + Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null; + if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) { + // Convert to unsigned load + ensureEvaluated(other); + return emitConvert2MemoryOp(Kind.Int, MOV_B2UI, access); + } + return null; + } + + default: + return null; + } + } + + @Override + public Value emitOrMemory(ValueNode x, ValueNode y, Access access) { + switch (access.nullCheckLocation().getValueKind()) { + case Int: + return emitBinaryMemory(IOR, true, x, y, access); + case Long: + return emitBinaryMemory(LOR, true, x, y, access); + default: + return null; + } + } + + @Override + public Value emitXorMemory(ValueNode x, ValueNode y, Access access) { + switch (access.nullCheckLocation().getValueKind()) { + case Int: + return emitBinaryMemory(IXOR, true, x, y, access); + case Long: + return emitBinaryMemory(LXOR, true, x, y, access); + default: + return null; + } + } + + @Override + public Value emitReinterpretMemory(Stamp stamp, Access access) { + PlatformKind to = gen.getLIRGenerator().getPlatformKind(stamp); + Kind from = access.nullCheckLocation().getValueKind(); + assert to != from : "should have been eliminated"; + + /* + * Conversions between integer to floating point types require moves between CPU and FPU + * registers. + */ + switch ((Kind) to) { + case Int: + switch (from) { + case Float: + return emitConvert2MemoryOp(to, MOV_F2I, access); + } + break; + case Long: + switch (from) { + case Double: + return emitConvert2MemoryOp(to, MOV_D2L, access); + } + break; + case Float: + switch (from) { + case Int: + return emitConvert2MemoryOp(to, MOV_I2F, access); + } + break; + case Double: + switch (from) { + case Long: + return emitConvert2MemoryOp(to, MOV_L2D, access); + } + break; + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public Value emitFloatConvertMemory(FloatConvert op, Access access) { + switch (op) { + case D2F: + return emitConvert2MemoryOp(Kind.Float, D2F, access); + case D2I: + return emitConvert2MemoryOp(Kind.Int, D2I, access); + case D2L: + return emitConvert2MemoryOp(Kind.Long, D2L, access); + case F2D: + return emitConvert2MemoryOp(Kind.Double, F2D, access); + case F2I: + return emitConvert2MemoryOp(Kind.Int, F2I, access); + case F2L: + return emitConvert2MemoryOp(Kind.Long, F2L, access); + case I2D: + return emitConvert2MemoryOp(Kind.Double, I2D, access); + case I2F: + return emitConvert2MemoryOp(Kind.Float, I2F, access); + case L2D: + return emitConvert2MemoryOp(Kind.Double, L2D, access); + case L2F: + return emitConvert2MemoryOp(Kind.Float, L2F, access); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public Value emitSignExtendMemory(Access access, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return null; + } else if (toBits > 32) { + // sign extend to 64 bits + switch (fromBits) { + case 8: + return emitConvert2MemoryOp(Kind.Long, B2L, access); + case 16: + return emitConvert2MemoryOp(Kind.Long, S2L, access); + case 32: + return emitConvert2MemoryOp(Kind.Long, I2L, access); + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } else { + + // sign extend to 32 bits (smaller values are internally represented as 32 bit values) + switch (fromBits) { + case 8: + return emitConvert2MemoryOp(Kind.Int, B2I, access); + case 16: + return emitConvert2MemoryOp(Kind.Int, S2I, access); + case 32: + return null; + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } + } + + @Override + public Value emitNarrowMemory(int resultBits, Access access) { + // TODO + return null; + } + + @Override + public Value emitZeroExtendMemory(int inputBits, int resultBits, Access access) { + assert resultBits == 32 || resultBits == 64; + Kind memoryKind = access.nullCheckLocation().getValueKind(); + if (memoryKind.getBitCount() != inputBits && !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; + } + if (memoryKind == Kind.Short) { + memoryKind = Kind.Char; + } + evaluateDeferred(); + return gen.getLIRGenerator().emitZeroExtendMemory(memoryKind, resultBits, makeAddress(access), getState(access)); + } + + public boolean emitIfMemory(IfNode x, Access access) { + return emitBranchMemory(x.condition(), access, gen.getLIRBlock(x.trueSuccessor()), gen.getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); + } + + private boolean emitBranchMemory(LogicNode node, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + if (node instanceof IsNullNode) { + // can't do anything interesting. + return false; + } else if (node instanceof CompareNode) { + CompareNode compare = (CompareNode) node; + return emitCompareBranchMemory(compare, access, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else if (node instanceof LogicConstantNode) { + return false; + } else if (node instanceof IntegerTestNode) { + return emitIntegerTestBranchMemory((IntegerTestNode) node, access, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else { + throw GraalInternalError.unimplemented(node.toString()); + } + } + + public boolean emitCompareBranchMemory(CompareNode compare, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + return emitCompareBranchMemory(compare.x(), compare.y(), access, compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + public boolean emitIntegerTestBranchMemory(IntegerTestNode test, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + return emitIntegerTestBranchMemory(test.x(), test.y(), access, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + private boolean emitIntegerTestBranchMemory(ValueNode left, ValueNode right, Access access, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) { + assert left == access || right == access; + ValueNode other = left == access ? right : left; + Kind kind = access.nullCheckLocation().getValueKind(); + if (other.isConstant()) { + Constant constant = other.asConstant(); + if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) { + // Only imm32 as long + return false; + } + ensureEvaluated(other); + gen.append(new AMD64TestMemoryOp(makeAddress(access), constant, getState(access))); + } else { + evaluateDeferred(); + gen.append(new AMD64TestMemoryOp(makeAddress(access), gen.operand(other), getState(access))); + } + + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return true; + } + + protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, + double trueLabelProbability) { + assert left == access || right == access; + ValueNode other = left == access ? right : left; + Kind kind = access.nullCheckLocation().getValueKind(); + boolean mirrored = false; + + if (other.isConstant()) { + Constant constant = other.asConstant(); + if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) { + // Only imm32 as long + return false; + } + if (kind.isNumericFloat()) { + Debug.log("Skipping constant compares for float kinds"); + return false; + } + if (kind == Kind.Object) { + if (!constant.isNull()) { + Debug.log("Skipping constant compares for Object kinds"); + return false; + } + } + if (kind != kind.getStackKind()) { + Debug.log("Skipping constant compares for stack kinds"); + return false; + } + ensureEvaluated(other); + gen.getLIRGenerator().emitCompareMemoryConOp(kind, makeAddress(access), constant, getState(access)); + mirrored = right == access; + } else { + if (kind != kind.getStackKind()) { + // Register compares only work for stack kinds + Debug.log("Register compares only work for stack kinds"); + return false; + } else if (kind == Kind.Object) { + // Can't compare against objects since they require encode/decode + Debug.log("Skipping compares for Object kinds"); + return false; + } + + evaluateDeferred(); + gen.getLIRGenerator().emitCompareRegMemoryOp(kind, gen.operand(other), makeAddress(access), getState(access)); + mirrored = left == access; + } + + Condition finalCondition = mirrored ? cond.mirror() : cond; + switch (kind.getStackKind()) { + case Long: + case Int: + case Object: + gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); + return true; + case Float: + case Double: + gen.append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); + return true; + default: + throw GraalInternalError.shouldNotReachHere("" + kind.getStackKind()); + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.amd64; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; + +public abstract class AMD64NodeLIRGenerator extends NodeLIRGenerator { + + public AMD64NodeLIRGenerator(StructuredGraph graph, LIRGenerationResult res, LIRGenerator gen) { + super(graph, res, gen); + } + + protected MemoryArithmeticLIRLowerer memoryPeephole; + + @Override + public MemoryArithmeticLIRLowerer getMemoryLowerer() { + if (memoryPeephole == null) { + // Use the generic one + memoryPeephole = new AMD64MemoryPeephole(this); + } + return memoryPeephole; + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + AllocatableValue targetAddress = AMD64.rax.asValue(); + gen.emitMove(targetAddress, operand(callTarget.computedAddress())); + append(new AMD64Call.IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState)); + } + + @Override + public void emitNullCheck(ValueNode v, DeoptimizingNode deopt) { + assert v.getKind() == Kind.Object : v + " - " + v.stamp() + " @ " + deopt; + append(new AMD64Move.NullCheckOp(gen.load(operand(v)), gen.state(deopt))); + } + + @Override + protected boolean peephole(ValueNode valueNode) { + if ((valueNode instanceof IntegerDivNode) || (valueNode instanceof IntegerRemNode)) { + FixedBinaryNode divRem = (FixedBinaryNode) valueNode; + FixedNode node = divRem.next(); + while (node instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node; + if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) { + FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode; + if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && operand(otherDivRem) == null) { + Value[] results = ((AMD64LIRGenerator) gen).emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode); + if (divRem instanceof IntegerDivNode) { + setResult(divRem, results[0]); + setResult(otherDivRem, results[1]); + } else { + setResult(divRem, results[1]); + setResult(otherDivRem, results[0]); + } + return true; + } + } + node = fixedWithNextNode.next(); + } + } + return false; + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + JavaType[] sig = new JavaType[node.arguments().size()]; + for (int i = 0; i < sig.length; i++) { + sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess()); + } + + Value[] parameters = visitInvokeArguments(res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, gen.target(), false), node.arguments()); + append(new AMD64BreakpointOp(parameters)); + } + + @Override + public void visitInfopointNode(InfopointNode i) { + append(new InfopointOp(gen.stateFor(i.getState()), i.reason)); + } + + @Override + public AMD64LIRGenerator getLIRGenerator() { + return (AMD64LIRGenerator) gen; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,6 +39,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; +import com.oracle.graal.gpu.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.hsail.*; import com.oracle.graal.hotspot.meta.*; @@ -131,16 +132,21 @@ // Special overrides for the testGeneratedxxx routines which set // required graal options that we need to run any junit test + + private OverrideScope getOverrideScope() { + return OptionValue.override(GraalOptions.InlineEverything, true, accessibleRemoveNeverExecutedCode, false); + } + @Override public void testGeneratedHsail() { - try (OverrideScope s = OptionValue.override(GraalOptions.InlineEverything, true, accessibleRemoveNeverExecutedCode, false)) { + try (OverrideScope s = getOverrideScope()) { super.testGeneratedHsail(); } } @Override public void testGeneratedHsailUsingLambdaMethod() { - try (OverrideScope s = OptionValue.override(GraalOptions.InlineEverything, true, accessibleRemoveNeverExecutedCode, false)) { + try (OverrideScope s = getOverrideScope()) { super.testGeneratedHsailUsingLambdaMethod(); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Sun Mar 30 16:08:33 2014 +0200 @@ -118,6 +118,8 @@ dispatchMode = DispatchMode.SEQ; hsailMode = HsailMode.COMPILED; useLambdaMethod = false; + // Control which okra instances can run the tests (is Simulator is static). + onSimulator = OkraContext.isSimulator(); this.okraLibExists = okraLibExists; } @@ -609,8 +611,12 @@ fail("wrong arguments invoking " + testMethod + ", check number and type of args passed to dispatchMethodKernel"); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); - String errstr = testMethod + " threw an exception on gid=" + rangeIndex + ", exception was " + cause; - fail(errstr); + if (cause instanceof RuntimeException) { + throw ((RuntimeException) cause); + } else { + String errstr = testMethod + " threw a checked exception on gid=" + rangeIndex + ", exception was " + cause; + fail(errstr); + } } catch (Exception e) { fail("Unknown exception " + e + " invoking " + testMethod); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java --- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,11 +26,11 @@ import org.junit.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.gpu.*; import com.oracle.graal.hotspot.hsail.*; import com.oracle.graal.hsail.*; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchBase.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; + +/** + * Base Class for tests that deopt but then catch the exception in the run routine itself. + */ +public abstract class BoundsCatchBase extends GraalKernelTester { + + abstract int getGlobalSize(); + + final int num = getGlobalSize(); + @Result int[] outArray = new int[num]; + + void setupArrays() { + for (int i = 0; i < num; i++) { + outArray[i] = -i; + } + } + + // Note: could not push the whole run routine here because + // problems with indirect call to getDeoptGid + int getOutval(int gid) { + int adjustment = 0; + int tmp = gid + 10; + while (tmp > gid) { + adjustment += tmp; + tmp--; + } + int outval = (outArray[gid] * -1) + adjustment; + return outval; + } + + @Override + public void runTest() { + setupArrays(); + + // we should not get an exception escaping from the kernel + dispatchMethodKernel(num); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany16384Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany16384Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 16384, deopt on many gids but then catch the exception in the run routine itself. + */ +public class BoundsCatchMany16384Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 16384; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany20000Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany20000Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 20000, deopt on many gids but then catch the exception in the run routine itself. + */ +public class BoundsCatchMany20000Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 20000; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany5000Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany5000Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 5000, deopt on many gids but then catch the exception in the run routine itself. + */ +public class BoundsCatchMany5000Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 5000; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany8192Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany8192Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 8192, deopt on many gids but then catch the exception in the run routine itself. + */ +public class BoundsCatchMany8192Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 8192; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany987654HighTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany987654HighTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 987654, deopt on many gids but then catch the exception in the run routine itself + * deopt ids are at the high end. + */ +public class BoundsCatchMany987654HighTest extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 987654; + } + + boolean isMyDeoptGid(int gid) { + return (gid > getGlobalSize() - 4096 && gid % 512 == 1); + } + + // copied run routine here because otherwise polymorphic calls to isDeoptGid + @Override + public void run(int gid) { + int outval = getOutval(gid); + try { + int index = (isMyDeoptGid(gid) ? num + 1 : gid); + outArray[index] = outval; + } catch (ArrayIndexOutOfBoundsException e) { + // set up so we can detect if we go thru here twice + outArray[gid] += outval; + // note: cannot record the exceptiongid here for many deopts in parallel + } + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany987654Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany987654Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 987654, deopt on many gids but then catch the exception in the run routine itself. + */ +public class BoundsCatchMany987654Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 987654; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany99999Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMany99999Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 99999, deopt on many gids but then catch the exception in the run routine itself. + */ +public class BoundsCatchMany99999Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 99999; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchManyBase.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +/** + * Base Class for tests that deopt on multiple gids gid but then catches the exception in the run + * routine itself. + */ +public abstract class BoundsCatchManyBase extends BoundsCatchBase { + + boolean isDeoptGid(int gid) { + return (gid < 4096 && gid % 512 == 1); + } + + @Override + public int getMisMatchLimit() { + return 1000; + } + + public void run(int gid) { + int outval = getOutval(gid); + try { + int index = (isDeoptGid(gid) ? num + 1 : gid); + outArray[index] = outval; + } catch (ArrayIndexOutOfBoundsException e) { + // set up so we can detect if we go thru here twice + outArray[gid] += outval; + // note: cannot record the exceptiongid here for many deopts in parallel + } + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMost1000Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMost1000Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 1000, deopt on almost all gids but then catch the exception in the run routine + * itself. + */ +public class BoundsCatchMost1000Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 1000; + } + + boolean isMyDeoptGid(int gid) { + return (gid % 100 != 1); + } + + // copied run routine here because otherwise polymorphic calls to isDeoptGid + @Override + public void run(int gid) { + int outval = getOutval(gid); + try { + int index = (isMyDeoptGid(gid) ? num + 1 : gid); + outArray[index] = outval; + } catch (ArrayIndexOutOfBoundsException e) { + // set up so we can detect if we go thru here twice + outArray[gid] += outval; + // note: cannot record the exceptiongid here for many deopts in parallel + } + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMost20000Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchMost20000Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 20000, deopt on almost all gids but then catch the exception in the run routine + * itself. + */ +public class BoundsCatchMost20000Test extends BoundsCatchManyBase { + + @Override + int getGlobalSize() { + return 20000; + } + + boolean isMyDeoptGid(int gid) { + return (gid % 100 != 1); + } + + // copied run routine here because otherwise polymorphic calls to isDeoptGid + @Override + public void run(int gid) { + int outval = getOutval(gid); + try { + int index = (isMyDeoptGid(gid) ? num + 1 : gid); + outArray[index] = outval; + } catch (ArrayIndexOutOfBoundsException e) { + // set up so we can detect if we go thru here twice + outArray[gid] += outval; + // note: cannot record the exceptiongid here for many deopts in parallel + } + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle16384Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle16384Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 16384, deopt on a single gid but then catch the exception in the run routine + * itself. + */ +public class BoundsCatchSingle16384Test extends BoundsCatchSingleBase { + + @Override + int getGlobalSize() { + return 16384; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle20000Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle20000Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 20000, deopt on a single gid but then catch the exception in the run routine + * itself. + */ +public class BoundsCatchSingle20000Test extends BoundsCatchSingleBase { + + @Override + int getGlobalSize() { + return 20000; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle5000Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle5000Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 5000, deopt on a single gid but then catch the exception in the run routine + * itself. + */ +public class BoundsCatchSingle5000Test extends BoundsCatchSingleBase { + + @Override + int getGlobalSize() { + return 5000; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle8192Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingle8192Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * For globalsize 8192, deopt on a single gid but then catch the exception in the run routine + * itself. + */ +public class BoundsCatchSingle8192Test extends BoundsCatchSingleBase { + + @Override + int getGlobalSize() { + return 8192; + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingleBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCatchSingleBase.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +/** + * Base Class for tests that deopt on a single gid but then catch the exception in the run routine + * itself. + */ +public abstract class BoundsCatchSingleBase extends BoundsCatchBase { + + int getDeoptGid() { + return 512; + } + + boolean isDeoptGid(int gid) { + return (gid == getDeoptGid()); + } + + @Result public int exceptionGid; + + public void run(int gid) { + int outval = getOutval(gid); + try { + int index = (isDeoptGid(gid) ? num + 1 : gid); + outArray[index] = outval; + } catch (ArrayIndexOutOfBoundsException e) { + // set up so we can detect if we go thru here twice + outArray[gid] -= outval; + exceptionGid = gid; + } + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckDoubleNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckDoubleNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception + * back to the java code. + */ +public class BoundsCheckDoubleNonZeroBciTest extends SingleExceptionTestBase { + + static final int num = 20; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + double[] outArray = new double[num]; + + void setupArrays(double[] in1, double[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -i; + } + } + + static double dummyDouble = 10; + + public static void run(double[] out, double[] ina, double[] inb, int gid) { + // This will fail when gid+1==num + double adjustment = 0; + double tmp = dummyDouble; + while (tmp-- >= 0) { + adjustment += tmp; + } + out[gid + 1] = ina[gid] + inb[gid] + adjustment; + } + + @Override + public void runTest() { + double[] inArray1 = new double[num]; + double[] inArray2 = new double[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckFailsInMiddleTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckFailsInMiddleTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception + * back to the java code, in the middle of the array. + */ +public class BoundsCheckFailsInMiddleTest extends SingleExceptionTestBase { + static final int num = 128; // * 256; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + int[] outArray = new int[num]; + static final int abortingGid = (new java.util.Random()).nextInt(num / 4); + + void setupArrays(int[] in1, int[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -99; + } + } + + public static void run(int[] out, int[] ina, int[] inb, int gid) { + // Throw in the middle of doing the work + out[gid == abortingGid ? (gid + num) : gid] = ina[gid] + inb[gid]; + } + + @Override + public void runTest() { + int[] inArray1 = new int[num]; + int[] inArray2 = new int[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckFloatNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckFloatNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception + * back to the java code. + */ +public class BoundsCheckFloatNonZeroBciTest extends SingleExceptionTestBase { + + static final int num = 20; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + float[] outArray = new float[num]; + + void setupArrays(float[] in1, float[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -i; + } + } + + static float dummyFloat = 10; + + public static void run(float[] out, float[] ina, float[] inb, int gid) { + // This will fail when gid+1==num + float adjustment = 0; + float tmp = dummyFloat; + while (tmp-- >= 0) { + adjustment += tmp; + } + out[gid + 1] = ina[gid] + inb[gid] + adjustment; + } + + @Override + public void runTest() { + float[] inArray1 = new float[num]; + float[] inArray2 = new float[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckInlineTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckInlineTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * + * @author ecaspole + */ +public class BoundsCheckInlineTest extends SingleExceptionTestBase { + + static final int num = 20; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + int[] outArray = new int[num]; + + void setupArrays(int[] in1, int[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -i; + } + } + + static volatile int dummy; + + static void writesum(int[] out, int gid, int val) { + out[gid + 1] = val; + } + + public static void run(int[] out, int[] ina, int[] inb, int gid) { + // This will fail when gid+1==num + writesum(out, gid, ina[gid] + inb[gid]); + } + + @Override + public void runTest() { + int[] inArray1 = new int[num]; + int[] inArray2 = new int[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckLongNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckLongNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception + * back to the java code. + */ +public class BoundsCheckLongNonZeroBciTest extends SingleExceptionTestBase { + + static final int num = 20; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + long[] outArray = new long[num]; + + void setupArrays(long[] in1, long[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -i; + } + } + + static long dummyLong = 10; + + public static void run(long[] out, long[] ina, long[] inb, int gid) { + // This will fail when gid+1==num + long adjustment = 0x1234567890abcdefL; + long tmp = dummyLong; + while (tmp-- >= 0) { + adjustment += tmp; + } + out[gid + 1] = ina[gid] + inb[gid] + adjustment; + } + + @Override + public void runTest() { + long[] inArray1 = new long[num]; + long[] inArray2 = new long[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckNonZeroBciInstanceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckNonZeroBciInstanceTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception + * back to the java code. + */ +public class BoundsCheckNonZeroBciInstanceTest extends SingleExceptionTestBase { + + static final int num = 20; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + int[] outArray = new int[num]; + int[] inArray1 = new int[num]; + int[] inArray2 = new int[num]; + + void setupArrays(int[] in1, int[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -i; + } + } + + int dummyInt = 10; + + public void run(int gid) { + // This will fail when gid+1==num + int adjustment = 0; + int tmp = dummyInt; + while (tmp-- >= 0) { + adjustment += tmp; + } + outArray[gid + 1] = inArray1[gid] + inArray2[gid] + adjustment; + } + + @Override + public void runTest() { + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception + * back to the java code. + */ +public class BoundsCheckNonZeroBciTest extends SingleExceptionTestBase { + + static final int num = 20; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + int[] outArray = new int[num]; + + void setupArrays(int[] in1, int[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -i; + } + } + + static int dummyInt = 10; + + public static void run(int[] out, int[] ina, int[] inb, int gid) { + // This will fail when gid+1==num + int adjustment = 0; + int tmp = dummyInt; + while (tmp-- >= 0) { + adjustment += tmp; + } + out[gid + 1] = ina[gid] + inb[gid] + adjustment; + } + + @Override + public void runTest() { + int[] inArray1 = new int[num]; + int[] inArray2 = new int[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BoundsCheckTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes an ArrayIndexOutOfBoundsException to test throwing the exception + * back to the java code. + */ +public class BoundsCheckTest extends SingleExceptionTestBase { + + static final int num = 20; + // note: outArray not marked as @Result because we can't predict + // which workitems will get done in parallel execution + int[] outArray = new int[num]; + + void setupArrays(int[] in1, int[] in2) { + for (int i = 0; i < num; i++) { + in1[i] = i; + in2[i] = i + 1; + outArray[i] = -i; + } + } + + public static void run(int[] out, int[] ina, int[] inb, int gid) { + // This will fail when gid+1==num + out[gid + 1] = ina[gid] + inb[gid]; + } + + @Override + public void runTest() { + int[] inArray1 = new int[num]; + int[] inArray2 = new int[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ClassCastNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ClassCastNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes a ClassCastException to test throwing the exception back to the + * java code. + */ +public class ClassCastNonZeroBciTest extends SingleExceptionTestBase { + + static final int num = 20; + + static class BasePoint { + int x; + int y; + + public BasePoint(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + } + + static class MyPoint extends BasePoint { + public MyPoint(int x, int y) { + super(x, y); + } + } + + BasePoint[] inputs = new BasePoint[num]; + MyPoint[] outputs = new MyPoint[num]; + + void setupArrays() { + for (int i = 0; i < num; i++) { + inputs[i] = new MyPoint(i, i + 1); + } + inputs[2] = new BasePoint(1, 1); + } + + public void run(int gid) { + // gid 2 should always throw ClassCastException + int adjustment = 0; + int tmp = gid; + while (tmp-- >= 0) { + adjustment += tmp; + } + MyPoint mp = (MyPoint) inputs[gid]; + mp.x = mp.y + adjustment; + outputs[gid] = mp; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(num); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ClassCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ClassCastTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test deliberately causes a ClassCastException to test throwing the exception back to the + * java code. + */ +public class ClassCastTest extends SingleExceptionTestBase { + + static final int num = 20; + + static class BasePoint { + int x; + int y; + + public BasePoint(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + } + + static class MyPoint extends BasePoint { + public MyPoint(int x, int y) { + super(x, y); + } + } + + BasePoint[] inputs = new BasePoint[num]; + MyPoint[] outputs = new MyPoint[num]; + + void setupArrays() { + for (int i = 0; i < num; i++) { + inputs[i] = new MyPoint(i, i + 1); + } + inputs[2] = new BasePoint(1, 1); + } + + public void run(int gid) { + // gid 2 should always throw ClassCastException + MyPoint mp = (MyPoint) inputs[gid]; + mp.x = mp.y + 2; + outputs[gid] = mp; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(num); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCatchNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCatchNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test tests an int stream where we deliberately cause a NPE to test throwing the exception + * back to the java code. In addition, it is set up so the bci of the exception point is not zero. + */ +public class IntStreamNullCatchNonZeroBciTest extends SingleExceptionTestBase { + + static final int num = 20; + + static class BasePoint { + int x; + int y; + + public BasePoint(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + } + + static class MyPoint extends BasePoint { + public MyPoint(int x, int y) { + super(x, y); + } + } + + BasePoint[] inputs = new BasePoint[num]; + MyPoint[] outputs = new MyPoint[num]; + + void setupArrays() { + for (int i = 0; i < num; i++) { + inputs[i] = new MyPoint(i, i + 1); + } + inputs[10] = null; + } + + @Result public int nullSeenGid; + @Result public int nullSeenAdjustment; + + public void run(int gid) { + // gid 10 should always throw NPE + MyPoint mp = (MyPoint) inputs[gid]; + int adjustment = 0; + int tmp = gid; + while (tmp-- >= 0) { + adjustment += tmp; + } + try { + mp.x = mp.y + adjustment; + } catch (NullPointerException e) { + nullSeenGid = gid; + nullSeenAdjustment = adjustment; + } + outputs[gid] = mp; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(num); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCheckNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCheckNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test tests an int stream where we deliberately cause a NPE to test throwing the exception + * back to the java code. In addition, it is set up so the bci of the exception point is not zero. + */ +public class IntStreamNullCheckNonZeroBciTest extends SingleExceptionTestBase { + + static final int num = 20; + + static class BasePoint { + int x; + int y; + + public BasePoint(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + } + + static class MyPoint extends BasePoint { + public MyPoint(int x, int y) { + super(x, y); + } + } + + BasePoint[] inputs = new BasePoint[num]; + MyPoint[] outputs = new MyPoint[num]; + + void setupArrays() { + for (int i = 0; i < num; i++) { + inputs[i] = new MyPoint(i, i + 1); + } + inputs[10] = null; + } + + public void run(int gid) { + // gid 10 should always throw NPE + MyPoint mp = (MyPoint) inputs[gid]; + int adjustment = 0; + int tmp = gid; + while (tmp-- >= 0) { + adjustment += tmp; + } + mp.x = mp.y + adjustment; + outputs[gid] = mp; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(num); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullCheckTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * This test tests an int stream where we deliberately cause a NPE to test throwing the exception + * back to the java code. + */ +public class IntStreamNullCheckTest extends SingleExceptionTestBase { + + static final int num = 20; + + static class BasePoint { + int x; + int y; + + public BasePoint(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + } + + static class MyPoint extends BasePoint { + public MyPoint(int x, int y) { + super(x, y); + } + } + + BasePoint[] inputs = new BasePoint[num]; + MyPoint[] outputs = new MyPoint[num]; + + void setupArrays() { + for (int i = 0; i < num; i++) { + inputs[i] = new MyPoint(i, i + 1); + } + inputs[10] = null; + } + + public void run(int gid) { + // gid 10 should always throw NPE + MyPoint mp = (MyPoint) inputs[gid]; + mp.x = mp.y + 2; + outputs[gid] = mp; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(num); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullNonArrayParamCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullNonArrayParamCheckTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * Tests one of the kernel parameters being null. + */ +public class IntStreamNullNonArrayParamCheckTest extends SingleExceptionTestBase { + + static final int num = 20; + @Result protected int[] outArray = new int[num]; + + static class MyObj { + public int val; + } + + public static void run(int[] out, int[] ina, MyObj adjustment, int gid) { + out[gid] = ina[gid] + adjustment.val; + } + + @Override + public void runTest() { + int[] inArray1 = new int[num]; + int[] inArray2 = new int[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, inArray1, null); + } catch (Exception e) { + recordException(e); + } + } + + void setupArrays(int[] in1, int[] in2) { + for (int i = 0; i < num; i++) { + // Fill input arrays with a mix of positive and negative values. + in1[i] = i < num / 2 ? i + 1 : -(i + 1); + in2[i] = (i & 1) == 0 ? in1[i] + 10 : -(in1[i] + 10); + outArray[i] = -i; + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullParamCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/IntStreamNullParamCheckTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; + +/** + * Tests one of the kernel parameters being null. + */ +public class IntStreamNullParamCheckTest extends SingleExceptionTestBase { + + static final int num = 20; + @Result protected int[] outArray = new int[num]; + + public static void run(int[] out, int[] ina, int[] inb, int gid) { + out[gid] = ina[gid] + inb[gid]; + } + + @Override + public void runTest() { + int[] inArray1 = new int[num]; + int[] inArray2 = new int[num]; + setupArrays(inArray1, inArray2); + + try { + dispatchMethodKernel(num, outArray, null, inArray2); + } catch (Exception e) { + recordException(e); + } + } + + void setupArrays(int[] in1, int[] in2) { + for (int i = 0; i < num; i++) { + // Fill input arrays with a mix of positive and negative values. + in1[i] = i < num / 2 ? i + 1 : -(i + 1); + in2[i] = (i & 1) == 0 ? in1[i] + 10 : -(in1[i] + 10); + outArray[i] = -i; + } + } + + @Test + public void test() { + super.testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/SingleExceptionTestBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/SingleExceptionTestBase.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; + +/** + * + * @author ecaspole + */ +public abstract class SingleExceptionTestBase extends GraalKernelTester { + + @Result Class exceptionClass; + @Result String exceptionString; + @Result StackTraceElement firstStackTraceElement; + + void recordException(Exception e) { + // for now we just test that the class the of the exception + // matches for the java and gpu side + exceptionClass = e.getClass(); + // exception = e; + StackTraceElement[] elems = e.getStackTrace(); + firstStackTraceElement = elems[0]; + // for tests where the exception was in the method parameters + // ignore the firstStackTraceElement matching + if (firstStackTraceElement.getClassName().contains("KernelTester")) { + firstStackTraceElement = null; + } + for (StackTraceElement elem : elems) { + if (elem.toString().contains("KernelTester")) { + break; + } + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMandelBoundsCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMandelBoundsCheckTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.Test; +import static org.junit.Assume.*; + +/** + * Unit test that simulates the Mandelbrot application. The run method here is a static method + * version of the original mandel kernel and the invoke parameters are for the starting point of the + * mandel demo. Note: this will likely not pass the junit test on real hardware, but should pass on + * the simulator. + */ +public class StaticMandelBoundsCheckTest extends SingleExceptionTestBase { + + static final int initWidth = 768; + static final int initHeight = initWidth; + static final int maxIterations = 64; + static final int range = initWidth * initHeight; + private int[] rgb = new int[range]; + + public static void run(int[] rgb, int[] pallette, float xoffset, float yoffset, float scale, int gid) { + final int width = initWidth; + final int height = initHeight; + float lx = (((gid % width * scale) - ((scale / 2) * width)) / width) + xoffset; + float ly = (((gid / width * scale) - ((scale / 2) * height)) / height) + yoffset; + int count = 0; + float zx = lx; + float zy = ly; + float newzx = 0f; + + // Iterate until the algorithm converges or until maxIterations are reached. + while (count < maxIterations && zx * zx + zy * zy < 8) { + newzx = zx * zx - zy * zy + lx; + zy = 2 * zx * zy + ly; + zx = newzx; + count++; + } + rgb[gid + 1] = pallette[count]; // will cause exception on last of range + } + + void setupPalette(int[] in) { + for (int i = 0; i < in.length; i++) { + in[i] = i; + } + } + + @Override + public void runTest() { + int[] palette = new int[256]; + setupPalette(palette); + /** + * Call it for a range, specifying testmethod args (but not the fields it uses or the gid + * argument). + */ + try { + dispatchMethodKernel(range, rgb, palette, -1f, 0f, 3f); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + assumeTrue(runningOnSimulator()); + testGeneratedHsail(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamClassCastNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamClassCastNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests an object array stream with one element being of the wrong class. + */ +public class Vec3ObjStreamClassCastNonZeroBciTest extends SingleExceptionTestBase { + + static final int NUM = 20; + + public Vec3[] inArray = new Vec3[NUM]; + + static class MyVec3 extends Vec3 { + public MyVec3(float x, float y, float z) { + super(x, y, z); + } + } + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + inArray[i] = new MyVec3(i, i + 1, -1); + } + // insert one wrong type + inArray[10] = new Vec3(10, 11, -1); + } + + int dummyInt = 10; + + /** + * The "kernel" method we will be testing. For Array Stream, an object from the array will be + * the last parameter + */ + public void run(Vec3 vec3) { + int adjustment = 0; + int tmp = dummyInt; + while (tmp-- >= 0) { + adjustment += tmp; + } + MyVec3 myvec3 = (MyVec3) vec3; + myvec3.z = myvec3.x + myvec3.y + adjustment; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(inArray); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamClassCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamClassCastTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests an object array stream with one element being of the wrong class. + */ +public class Vec3ObjStreamClassCastTest extends SingleExceptionTestBase { + + static final int NUM = 20; + + public Vec3[] inArray = new Vec3[NUM]; + + static class MyVec3 extends Vec3 { + public MyVec3(float x, float y, float z) { + super(x, y, z); + } + } + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + inArray[i] = new MyVec3(i, i + 1, -1); + } + // insert one wrong type + inArray[10] = new Vec3(10, 11, -1); + } + + /** + * The "kernel" method we will be testing. For Array Stream, an object from the array will be + * the last parameter + */ + public void run(Vec3 vec3) { + MyVec3 myvec3 = (MyVec3) vec3; + myvec3.z = myvec3.x + myvec3.y; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(inArray); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullCheckNonZeroBciTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullCheckNonZeroBciTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests an object array stream with one element being null. + */ +public class Vec3ObjStreamNullCheckNonZeroBciTest extends SingleExceptionTestBase { + + static final int NUM = 20; + + public Vec3[] inArray = new Vec3[NUM]; + + static class MyVec3 extends Vec3 { + public MyVec3(float x, float y, float z) { + super(x, y, z); + } + } + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + inArray[i] = new MyVec3(i, i + 1, -1); + } + // insert one null + inArray[10] = null; + } + + int dummyInt = 10; + + /** + * The "kernel" method we will be testing. For Array Stream, an object from the array will be + * the last parameter + */ + public void run(Vec3 vec3) { + int adjustment = 0; + int tmp = dummyInt; + while (tmp-- >= 0) { + adjustment += tmp; + } + vec3.z = vec3.x + vec3.y + adjustment; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(inArray); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullCheckTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests an object array stream with one element being null. + */ +public class Vec3ObjStreamNullCheckTest extends SingleExceptionTestBase { + + static final int NUM = 20; + + public Vec3[] inArray = new Vec3[NUM]; + + static class MyVec3 extends Vec3 { + public MyVec3(float x, float y, float z) { + super(x, y, z); + } + } + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + inArray[i] = new MyVec3(i, i + 1, -1); + } + // insert one null + inArray[10] = null; + } + + /** + * The "kernel" method we will be testing. For Array Stream, an object from the array will be + * the last parameter + */ + public void run(Vec3 vec3) { + vec3.z = vec3.x + vec3.y; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(inArray); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullParamCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Vec3ObjStreamNullParamCheckTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.graal.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests an object array stream with the object stream itself being null. + */ +public class Vec3ObjStreamNullParamCheckTest extends SingleExceptionTestBase { + + static final int NUM = 20; + + public Vec3[] inArray = new Vec3[NUM]; + + static class MyVec3 extends Vec3 { + public MyVec3(float x, float y, float z) { + super(x, y, z); + } + } + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + inArray[i] = new MyVec3(i, i + 1, -1); + } + // insert one null + inArray[10] = null; + } + + /** + * The "kernel" method we will be testing. For Array Stream, an object from the array will be + * the last parameter + */ + public void run(Vec3 vec3) { + MyVec3 myvec3 = (MyVec3) vec3; + myvec3.z = myvec3.x + myvec3.y; + } + + @Override + public void runTest() { + setupArrays(); + try { + dispatchMethodKernel(null); + } catch (Exception e) { + recordException(e); + } + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java --- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; @@ -54,7 +53,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; -import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.util.*; /** @@ -76,9 +74,9 @@ } } - public HSAILLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); - lir.setSpillMoveFactory(new HSAILSpillMoveFactory()); + public HSAILLIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); + lirGenRes.getLIR().setSpillMoveFactory(new HSAILSpillMoveFactory()); } @Override @@ -115,7 +113,11 @@ } } - protected HSAILAddressValue asAddressValue(Value address) { + public void emitData(AllocatableValue dst, byte[] data) { + throw GraalInternalError.unimplemented(); + } + + public HSAILAddressValue asAddressValue(Value address) { if (address instanceof HSAILAddressValue) { return (HSAILAddressValue) address; } else { @@ -173,7 +175,7 @@ append(new JumpOp(label)); } - protected static HSAILCompare mapKindToCompareOp(Kind kind) { + public static HSAILCompare mapKindToCompareOp(Kind kind) { switch (kind) { case Int: return ICMP; @@ -249,7 +251,7 @@ /** * Generates the LIR instruction for a negation operation. - * + * * @param input the value that is being negated * @return Variable that represents the result of the negation */ @@ -280,7 +282,7 @@ /** * Generates the LIR instruction for a bitwise NOT operation. - * + * * @param input the source operand * @return Variable that represents the result of the operation */ @@ -412,12 +414,6 @@ } @Override - protected boolean peephole(ValueNode valueNode) { - // No peephole optimizations for now. - return false; - } - - @Override public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) { Variable result = newVariable(a.getKind()); switch (a.getKind()) { @@ -522,7 +518,7 @@ /** * Generates the LIR instruction for a shift left operation. - * + * * @param a The value that is being shifted * @param b The shift amount * @return Variable that represents the result of the operation @@ -547,7 +543,7 @@ /** * Generates the LIR instruction for a shift right operation. - * + * * @param a The value that is being shifted * @param b The shift amount * @return Variable that represents the result of the operation @@ -572,7 +568,7 @@ /** * Generates the LIR instruction for an unsigned shift right operation. - * + * * @param a The value that is being shifted * @param b The shift amount * @return Variable that represents the result of the operation @@ -697,16 +693,6 @@ } @Override - protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - throw GraalInternalError.unimplemented(); - } - - @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - throw GraalInternalError.unimplemented(); - } - - @Override public void emitBitCount(Variable result, Value value) { if (value.getKind().getStackKind() == Kind.Int) { append(new HSAILBitManipulationOp(IPOPCNT, result, value)); @@ -727,7 +713,7 @@ /** * Emits the LIR code for the {@link HSAILArithmetic#ABS} operation. - * + * * @param input the source operand * @return Value representing the result of the operation */ @@ -740,7 +726,7 @@ /** * Emits the LIR code for the {@link HSAILArithmetic#CEIL} operation. - * + * * @param input the source operand * @return Value representing the result of the operation */ @@ -752,7 +738,7 @@ /** * Emits the LIR code for the {@link HSAILArithmetic#FLOOR} operation. - * + * * @param input the source operand * @return Value representing the result of the operation */ @@ -764,7 +750,7 @@ /** * Emits the LIR code for the {@link HSAILArithmetic#RINT} operation. - * + * * @param input the source operand * @return Value representing the result of the operation */ @@ -776,7 +762,7 @@ /** * Emits the LIR code for the {@link HSAILArithmetic#SQRT} operation. - * + * * @param input the source operand * @return value representing the result of the operation */ @@ -819,21 +805,21 @@ } @Override - protected void emitReturn(Value input) { + public void emitReturn(Value input) { append(new ReturnOp(input)); } /** * This routine handles the LIR code generation for switch nodes by calling * emitSequentialSwitch. - * + * * This routine overrides LIRGenerator.emitSwitch( ) which calls emitSequentialSwitch or * emitTableSwitch based on a heuristic. - * + * * The recommended approach in HSAIL for generating performant code for switch statements is to * emit a series of cascading compare and branches. Thus this routines always calls * emitSequentialSwitch, which implements this approach. - * + * * Note: Only IntegerSwitchNodes are currently supported. The IntegerSwitchNode is the node that * Graal generates for any switch construct appearing in Java bytecode. */ @@ -846,17 +832,17 @@ * Generates the LIR instruction for a switch construct that is meant to be assembled into a * series of cascading compare and branch instructions. This is currently the recommended way of * generating performant HSAIL code for switch constructs. - * + * * In Java bytecode the keys for switch statements are always ints. - * + * * The x86 backend also adds support for handling keys of type long or Object but these two * special cases are for handling the TypeSwitchNode, which is a node that the JVM produces for * handling operations related to method dispatch. We haven't yet added support for the * TypeSwitchNode, so for the time being we have added a check to ensure that the keys are of * type int. This also allows us to flag any test cases/execution paths that may trigger the * creation of a TypeSwitchNode which we don't support yet. - * - * + * + * * @param strategy the strategy used for this switch. * @param keyTargets array of branch targets for each of the cases. * @param defaultTarget the branch target for the default case. @@ -864,12 +850,12 @@ */ @Override protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { - if (key.getKind() == Kind.Int) { + if ((key.getKind() == Kind.Int) || (key.getKind() == Kind.Long)) { // Append the LIR instruction for generating compare and branch instructions. append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key)); } else { // Throw an exception if the keys aren't ints. - throw GraalInternalError.unimplemented("Switch statements are only supported for keys of type int"); + throw GraalInternalError.unimplemented("Switch statements are only supported for keys of type int or long, not " + key.getKind()); } } @@ -879,30 +865,8 @@ } @Override - public void visitBreakpointNode(BreakpointNode node) { - throw GraalInternalError.unimplemented(); - } - - @Override - public void visitSafepointNode(SafepointNode i) { - Debug.log("visitSafePointNode unimplemented"); - } - - @Override public void emitUnwind(Value operand) { throw GraalInternalError.unimplemented(); } - @Override - public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { - assert v.stamp() instanceof ObjectStamp; - Variable obj = newVariable(Kind.Object); - emitMove(obj, operand(v)); - append(new HSAILMove.NullCheckOp(obj, state(deopting))); - } - - @Override - public void visitInfopointNode(InfopointNode i) { - throw GraalInternalError.unimplemented(); - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,82 @@ +/* + * 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.compiler.hsail; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.hsail.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * This class implements the HSAIL specific portion of the LIR generator. + */ +public abstract class HSAILNodeLIRGenerator extends NodeLIRGenerator { + + public HSAILNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + super(graph, lirGenRes, lirGen); + } + + @Override + protected boolean peephole(ValueNode valueNode) { + // No peephole optimizations for now. + return false; + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + throw GraalInternalError.unimplemented(); + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + throw GraalInternalError.unimplemented(); + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + throw GraalInternalError.unimplemented(); + } + + @Override + public void visitSafepointNode(SafepointNode i) { + Debug.log("visitSafePointNode unimplemented"); + } + + @Override + public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { + assert v.stamp() instanceof ObjectStamp; + Variable obj = newVariable(Kind.Object); + gen.emitMove(obj, operand(v)); + append(new HSAILMove.NullCheckOp(obj, gen.state(deopting))); + } + + @Override + public void visitInfopointNode(InfopointNode i) { + throw GraalInternalError.unimplemented(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -66,6 +66,7 @@ return a.i + i; } + @Ignore("com.oracle.graal.graph.GraalInternalError: should not reach here: unhandled register type v3|z") @Test public void test2() { A a = new A(); @@ -79,6 +80,7 @@ return a.z; } + @Ignore("[CUDA] Check for malformed PTX kernel or incorrect PTX compilation options") @Test public void test3() { for (byte b : new byte[]{Byte.MIN_VALUE, -10, 0, 1, 2, 10, Byte.MAX_VALUE}) { @@ -92,6 +94,7 @@ return a.b + b; } + @Ignore("com.oracle.graal.graph.GraalInternalError: should not reach here: unhandled register type v5|s") @Test public void test4() { for (short s : new short[]{Short.MIN_VALUE, -10, 0, 1, 2, 10, Short.MAX_VALUE}) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXMethodInvalidation1Test.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXMethodInvalidation1Test.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXMethodInvalidation1Test.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,8 +24,8 @@ import org.junit.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.gpu.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.ptx.*; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.gpu.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.ptx.*; import com.oracle.graal.nodes.*; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,13 +29,10 @@ import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.ptx.PTXCompare.*; -import java.lang.reflect.*; - import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; @@ -64,7 +61,6 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.util.*; @@ -89,11 +85,11 @@ } } - public PTXLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); - lir.setSpillMoveFactory(new PTXSpillMoveFactory()); + public PTXLIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); + lirGenRes.getLIR().setSpillMoveFactory(new PTXSpillMoveFactory()); int callVariables = cc.getArgumentCount() + (cc.getReturn().equals(Value.ILLEGAL) ? 0 : 1); - lir.setFirstVariableNumber(callVariables); + lirGenRes.getLIR().setFirstVariableNumber(callVariables); nextPredRegNum = 0; } @@ -134,43 +130,6 @@ return value; } - @Override - public void emitPrologue(StructuredGraph graph) { - // Need to emit .param directives based on incoming arguments and return value - CallingConvention incomingArguments = cc; - Object returnObject = incomingArguments.getReturn(); - AllocatableValue[] params = incomingArguments.getArguments(); - int argCount = incomingArguments.getArgumentCount(); - - if (returnObject.equals(Value.ILLEGAL)) { - params = incomingArguments.getArguments(); - append(new PTXParameterOp(params, false)); - } else { - argCount = incomingArguments.getArgumentCount(); - params = new Variable[argCount + 1]; - for (int i = 0; i < argCount; i++) { - params[i] = incomingArguments.getArgument(i); - } - params[argCount] = (Variable) returnObject; - append(new PTXParameterOp(params, true)); - } - - for (ParameterNode param : graph.getNodes(ParameterNode.class)) { - int localIndex = param.index(); - Value paramValue = params[param.index()]; - int parameterIndex = localIndex; - if (!Modifier.isStatic(graph.method().getModifiers())) { - parameterIndex--; - } - Warp warpAnnotation = parameterIndex >= 0 ? MetaUtil.getParameterAnnotation(Warp.class, parameterIndex, graph.method()) : null; - if (warpAnnotation != null) { - setResult(param, emitWarpParam(paramValue.getKind().getStackKind(), warpAnnotation)); - } else { - setResult(param, emitLoadParam(paramValue.getKind().getStackKind(), paramValue, null)); - } - } - } - public Variable emitWarpParam(Kind kind, Warp annotation) { Variable result = newVariable(kind); Variable tid = newVariable(Kind.Char); @@ -208,6 +167,11 @@ } @Override + public void emitData(AllocatableValue dst, byte[] data) { + throw GraalInternalError.unimplemented(); + } + + @Override public PTXAddressValue emitAddress(Value base, long displacement, Value index, int scale) { AllocatableValue baseRegister; long finalDisp = displacement; @@ -533,12 +497,6 @@ } @Override - protected boolean peephole(ValueNode valueNode) { - // No peephole optimizations for now - return false; - } - - @Override public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) { Variable result = newVariable(a.getKind()); switch (a.getKind()) { @@ -805,16 +763,6 @@ } @Override - protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - throw GraalInternalError.unimplemented("PTXLIRGenerator.emitDirectCall()"); - } - - @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - throw GraalInternalError.unimplemented("PTXLIRGenerator.emitIndirectCall()"); - } - - @Override protected void emitForeignCall(ForeignCallLinkage callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { throw GraalInternalError.unimplemented("PTXLIRGenerator.emitForeignCall()"); } @@ -880,11 +828,11 @@ } @Override - protected void emitReturn(Value input) { + public void emitReturn(Value input) { append(new ReturnOp(input)); } - private void emitReturnNoVal() { + void emitReturnNoVal() { append(new ReturnNoValOp()); } @@ -903,38 +851,10 @@ } @Override - public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) { - throw GraalInternalError.unimplemented("PTXLIRGenerator.visitCompareAndSwap()"); - } - - @Override - public void visitBreakpointNode(BreakpointNode node) { - throw GraalInternalError.unimplemented("PTXLIRGenerator.visitBreakpointNode()"); - } - - @Override - public void visitSafepointNode(SafepointNode i) { - // LIRFrameState info = state(i); - // append(new PTXSafepointOp(info, runtime().config, this)); - Debug.log("visitSafePointNode unimplemented"); - } - - @Override public void emitUnwind(Value operand) { throw GraalInternalError.unimplemented("PTXLIRGenerator.emitUnwind()"); } - @Override - public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { - assert v.kind() == Kind.Object; - append(new PTXMove.NullCheckOp(load(operand(v)), state(deopting))); - } - - @Override - public void visitInfopointNode(InfopointNode i) { - throw GraalInternalError.unimplemented("PTXLIRGenerator.visitInfopointNode()"); - } - public Variable emitLoadParam(Kind kind, Value address, DeoptimizingNode deopting) { PTXAddressValue loadAddress = asAddress(address); @@ -979,16 +899,4 @@ return (new Variable(kind, 0)); } - @Override - public void visitReturn(ReturnNode x) { - AllocatableValue operand = Value.ILLEGAL; - if (x.result() != null) { - operand = resultOperandFor(x.result().kind()); - // Load the global memory address from return parameter - Variable loadVar = emitLoadReturnAddress(operand.getKind(), operand, null); - // Store result in global memory whose location is loadVar - emitStoreReturnValue(operand.getKind(), loadVar, operand(x.result()), null); - } - emitReturnNoVal(); - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,208 @@ +/* + * 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.compiler.ptx; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.ptx.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.java.*; + +/** + * This class implements the PTX specific portion of the LIR generator. + */ +public class PTXNodeLIRGenerator extends NodeLIRGenerator { + + // Number of the predicate register that can be used when needed. + // This value will be recorded and incremented in the LIR instruction + // that sets a predicate register. (e.g., CompareOp) + private int nextPredRegNum; + + public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class); + public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class); + + public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory { + + @Override + public LIRInstruction createMove(AllocatableValue result, Value input) { + throw GraalInternalError.unimplemented("PTXSpillMoveFactory.createMove()"); + } + } + + public PTXNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + super(graph, lirGenRes, lirGen); + } + + public int getNextPredRegNumber() { + return nextPredRegNum; + } + + @Override + public void emitPrologue(StructuredGraph graph) { + // Need to emit .param directives based on incoming arguments and return value + CallingConvention incomingArguments = gen.getCallingConvention(); + Object returnObject = incomingArguments.getReturn(); + AllocatableValue[] params = incomingArguments.getArguments(); + int argCount = incomingArguments.getArgumentCount(); + + if (returnObject.equals(Value.ILLEGAL)) { + params = incomingArguments.getArguments(); + append(new PTXParameterOp(params, false)); + } else { + argCount = incomingArguments.getArgumentCount(); + params = new Variable[argCount + 1]; + for (int i = 0; i < argCount; i++) { + params[i] = incomingArguments.getArgument(i); + } + params[argCount] = (Variable) returnObject; + append(new PTXParameterOp(params, true)); + } + + for (ParameterNode param : graph.getNodes(ParameterNode.class)) { + int localIndex = param.index(); + Value paramValue = params[param.index()]; + int parameterIndex = localIndex; + if (!Modifier.isStatic(graph.method().getModifiers())) { + parameterIndex--; + } + Warp warpAnnotation = parameterIndex >= 0 ? MetaUtil.getParameterAnnotation(Warp.class, parameterIndex, graph.method()) : null; + if (warpAnnotation != null) { + setResult(param, getGen().emitWarpParam(paramValue.getKind().getStackKind(), warpAnnotation)); + } else { + setResult(param, getGen().emitLoadParam(paramValue.getKind().getStackKind(), paramValue, null)); + } + } + } + + private PTXLIRGenerator getGen() { + return (PTXLIRGenerator) gen; + } + + @Override + protected > void emitPrologue(ResolvedJavaMethod method, BytecodeParser parser) { + // Need to emit .param directives based on incoming arguments and return value + CallingConvention incomingArguments = gen.getCallingConvention(); + Object returnObject = incomingArguments.getReturn(); + AllocatableValue[] params = incomingArguments.getArguments(); + int argCount = incomingArguments.getArgumentCount(); + + if (returnObject.equals(Value.ILLEGAL)) { + params = incomingArguments.getArguments(); + append(new PTXParameterOp(params, false)); + } else { + argCount = incomingArguments.getArgumentCount(); + params = new Variable[argCount + 1]; + for (int i = 0; i < argCount; i++) { + params[i] = incomingArguments.getArgument(i); + } + params[argCount] = (Variable) returnObject; + append(new PTXParameterOp(params, true)); + } + + Signature sig = method.getSignature(); + boolean isStatic = Modifier.isStatic(method.getModifiers()); + + for (int i = 0; i < sig.getParameterCount(!isStatic); i++) { + Value paramValue = params[i]; + int parameterIndex = i; + if (!isStatic) { + parameterIndex--; + } + Warp warpAnnotation = parameterIndex >= 0 ? MetaUtil.getParameterAnnotation(Warp.class, parameterIndex, method) : null; + if (warpAnnotation != null) { + // setResult(param, emitWarpParam(paramValue.getKind().getStackKind(), + // warpAnnotation)); + parser.setParameter(i, getGen().emitWarpParam(paramValue.getKind().getStackKind(), warpAnnotation)); + } else { + // setResult(param, emitLoadParam(paramValue.getKind().getStackKind(), paramValue, + // null)); + parser.setParameter(i, getGen().emitLoadParam(paramValue.getKind().getStackKind(), paramValue, null)); + } + } + } + + @Override + protected boolean peephole(ValueNode valueNode) { + // No peephole optimizations for now + return false; + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + throw GraalInternalError.unimplemented("PTXLIRGenerator.emitDirectCall()"); + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + throw GraalInternalError.unimplemented("PTXLIRGenerator.emitIndirectCall()"); + } + + @Override + public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) { + throw GraalInternalError.unimplemented("PTXLIRGenerator.visitCompareAndSwap()"); + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + throw GraalInternalError.unimplemented("PTXLIRGenerator.visitBreakpointNode()"); + } + + @Override + public void visitSafepointNode(SafepointNode i) { + // LIRFrameState info = state(i); + // append(new PTXSafepointOp(info, runtime().config, this)); + Debug.log("visitSafePointNode unimplemented"); + } + + @Override + public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { + assert v.getKind() == Kind.Object; + append(new PTXMove.NullCheckOp(gen.load(operand(v)), gen.state(deopting))); + } + + @Override + public void visitInfopointNode(InfopointNode i) { + throw GraalInternalError.unimplemented("PTXLIRGenerator.visitInfopointNode()"); + } + + @Override + public void visitReturn(ReturnNode x) { + AllocatableValue operand = Value.ILLEGAL; + if (x.result() != null) { + operand = gen.resultOperandFor(x.result().getKind()); + // Load the global memory address from return parameter + Variable loadVar = getGen().emitLoadReturnAddress(operand.getKind(), operand, null); + // Store result in global memory whose location is loadVar + getGen().emitStoreReturnValue(operand.getKind(), loadVar, operand(x.result()), null); + } + getGen().emitReturnNoVal(); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -56,12 +56,10 @@ import com.oracle.graal.lir.sparc.SPARCMove.MembarOp; import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp; import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp; -import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp; import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.util.*; @@ -78,9 +76,9 @@ } } - public SPARCLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); - lir.setSpillMoveFactory(new SPARCSpillMoveFactory()); + public SPARCLIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); + lirGenRes.getLIR().setSpillMoveFactory(new SPARCSpillMoveFactory()); } @Override @@ -132,6 +130,11 @@ } @Override + public void emitData(AllocatableValue dst, byte[] data) { + throw GraalInternalError.unimplemented(); + } + + @Override public SPARCAddressValue emitAddress(Value base, long displacement, Value index, int scale) { AllocatableValue baseRegister; long finalDisp = displacement; @@ -215,13 +218,7 @@ } @Override - protected boolean peephole(ValueNode valueNode) { - // No peephole optimizations for now - return false; - } - - @Override - protected void emitReturn(Value input) { + public void emitReturn(Value input) { append(new ReturnOp(input)); } @@ -918,35 +915,4 @@ append(new ReturnOp(Value.ILLEGAL)); } - @Override - public void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address) { - throw new InternalError("NYI"); - } - - @Override - public void visitBreakpointNode(BreakpointNode node) { - JavaType[] sig = new JavaType[node.arguments().size()]; - for (int i = 0; i < sig.length; i++) { - sig[i] = node.arguments().get(i).stamp().javaType(getMetaAccess()); - } - - Value[] parameters = visitInvokeArguments(frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false), node.arguments()); - append(new SPARCBreakpointOp(parameters)); - } - - @Override - public void emitUnwind(Value operand) { - throw new InternalError("NYI"); - } - - @Override - public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { - assert v.kind() == Kind.Object; - append(new NullCheckOp(load(operand(v)), state(deopting))); - } - - @Override - public void visitInfopointNode(InfopointNode i) { - throw new InternalError("NYI"); - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 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.compiler.sparc; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.lir.sparc.*; +import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +/** + * This class implements the SPARC specific portion of the LIR generator. + */ +public abstract class SPARCNodeLIRGenerator extends NodeLIRGenerator { + + public SPARCNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + super(graph, lirGenRes, lirGen); + } + + @Override + protected boolean peephole(ValueNode valueNode) { + // No peephole optimizations for now + return false; + } + + @Override + public void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address) { + throw new InternalError("NYI"); + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + JavaType[] sig = new JavaType[node.arguments().size()]; + for (int i = 0; i < sig.length; i++) { + sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess()); + } + + Value[] parameters = visitInvokeArguments(res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, gen.target(), false), node.arguments()); + append(new SPARCBreakpointOp(parameters)); + } + + @Override + public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { + assert v.getKind() == Kind.Object; + append(new NullCheckOp(gen.load(operand(v)), gen.state(deopting))); + } + + @Override + public void visitInfopointNode(InfopointNode i) { + throw new InternalError("NYI"); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/AllocSpy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/AllocSpy.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2011, 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.compiler.test; + +import static java.lang.Boolean.*; +import static java.lang.Integer.*; +import static java.lang.System.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import com.google.monitoring.runtime.instrumentation.*; + +/** + * Tool for analyzing allocations within a scope using the Java Allocation Instrumenter. + * Allocation records are aggregated per stack trace at an allocation site. The size of the stack + * trace is governed by the value of the "AllocSpy.ContextSize" system property (default is 5). + *

+ * Using this facility requires using -javaagent on the command line. For example: + * + *

+ * mx --vm server unittest -javaagent:lib/java-allocation-instrumenter.jar -dsa -DAllocSpy.ContextSize=6 BC_iadd2
+ * 
+ * + * @see #SampleBytes + * @see #SampleInstances + * @see #HistogramLimit + * @see #NameSize + * @see #BarSize + * @see #NumberSize + */ +final class AllocSpy implements AutoCloseable { + + static ThreadLocal current = new ThreadLocal<>(); + + private static final boolean ENABLED; + static { + boolean enabled = false; + try { + Field field = AllocationRecorder.class.getDeclaredField("instrumentation"); + field.setAccessible(true); + enabled = field.get(null) != null; + } catch (Exception e) { + } + ENABLED = enabled; + if (ENABLED) { + AllocationRecorder.addSampler(new GraalContextSampler()); + } + } + + static String prop(String sfx) { + return AllocSpy.class.getSimpleName() + "." + sfx; + } + + /** + * Determines if bytes per allocation site are recorded. + */ + private static final boolean SampleBytes = parseBoolean(getProperty(prop("SampleBytes"), "true")); + + /** + * Determines if allocations per allocation site are recorded. + */ + private static final boolean SampleInstances = parseBoolean(getProperty(prop("SampleInstances"), "true")); + + /** + * The size of context to record for each allocation site in terms of Graal frames. + */ + private static final int ContextSize = getInteger(prop("ContextSize"), 5); + + /** + * Only the {@code HistogramLimit} most frequent values are printed. + */ + private static final int HistogramLimit = getInteger(prop("HistogramLimit"), 40); + + /** + * The width of the allocation context column. + */ + private static final int NameSize = getInteger(prop("NameSize"), 50); + + /** + * The width of the histogram bar column. + */ + private static final int BarSize = getInteger(prop("BarSize"), 100); + + /** + * The width of the frequency column. + */ + private static final int NumberSize = getInteger(prop("NumberSize"), 10); + + final Object name; + final AllocSpy parent; + final Map bytesPerGraalContext = new HashMap<>(); + final Map instancesPerGraalContext = new HashMap<>(); + + public static AllocSpy open(Object name) { + if (ENABLED) { + return new AllocSpy(name); + } + return null; + } + + private AllocSpy(Object name) { + this.name = name; + parent = current.get(); + current.set(this); + } + + public void close() { + current.set(parent); + PrintStream ps = System.out; + ps.println("\n\nAllocation histograms for " + name); + if (SampleBytes) { + print(ps, bytesPerGraalContext, "BytesPerGraalContext", HistogramLimit, NameSize + 60, BarSize); + } + if (SampleInstances) { + print(ps, instancesPerGraalContext, "InstancesPerGraalContext", HistogramLimit, NameSize + 60, BarSize); + } + } + + private static void printLine(PrintStream printStream, char c, int lineSize) { + char[] charArr = new char[lineSize]; + Arrays.fill(charArr, c); + printStream.printf("%s%n", new String(charArr)); + } + + private static void print(PrintStream ps, Map map, String name, int limit, int nameSize, int barSize) { + if (map.isEmpty()) { + return; + } + + List list = new ArrayList<>(map.values()); + Collections.sort(list); + + // Sum up the total number of elements. + int total = 0; + for (CountedValue cv : list) { + total += cv.getCount(); + } + + // Print header. + ps.printf("%s has %d unique elements and %d total elements:%n", name, list.size(), total); + + int max = list.get(0).getCount(); + final int lineSize = nameSize + NumberSize + barSize + 10; + printLine(ps, '-', lineSize); + String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n"; + for (int i = 0; i < list.size() && i < limit; ++i) { + CountedValue cv = list.get(i); + int value = cv.getCount(); + char[] bar = new char[(int) (((double) value / (double) max) * barSize)]; + Arrays.fill(bar, '='); + String[] lines = String.valueOf(cv.getValue()).split("\\n"); + + String objectString = lines[0]; + if (objectString.length() > nameSize) { + objectString = objectString.substring(0, nameSize - 3) + "..."; + } + ps.printf(formatString, objectString, value, new String(bar)); + for (int j = 1; j < lines.length; j++) { + String line = lines[j]; + if (line.length() > nameSize) { + line = line.substring(0, nameSize - 3) + "..."; + } + ps.printf("| %-" + (nameSize - 2) + "s | %-" + NumberSize + "s | %-" + barSize + "s |%n", line, " ", " "); + + } + } + printLine(ps, '-', lineSize); + } + + CountedValue bytesPerGraalContext(String context) { + return getCounter(context, bytesPerGraalContext); + } + + CountedValue instancesPerGraalContext(String context) { + return getCounter(context, instancesPerGraalContext); + } + + protected static CountedValue getCounter(String desc, Map map) { + CountedValue count = map.get(desc); + if (count == null) { + count = new CountedValue(0, desc); + map.put(desc, count); + } + return count; + } + + private static final String[] Excluded = {AllocSpy.class.getName(), AllocationRecorder.class.getName()}; + + private static boolean excludeFrame(String className) { + for (String e : Excluded) { + if (className.startsWith(e)) { + return true; + } + } + return false; + } + + static class GraalContextSampler implements Sampler { + + public void sampleAllocation(int count, String desc, Object newObj, long size) { + AllocSpy scope = current.get(); + if (scope != null) { + StringBuilder sb = new StringBuilder(200); + Throwable t = new Throwable(); + int remainingGraalFrames = ContextSize; + for (StackTraceElement e : t.getStackTrace()) { + if (remainingGraalFrames < 0) { + break; + } + String className = e.getClassName(); + boolean isGraalFrame = className.contains(".graal."); + if (sb.length() != 0) { + append(sb.append('\n'), e); + } else { + if (!excludeFrame(className)) { + sb.append("type=").append(desc); + if (count != 1) { + sb.append("[]"); + } + append(sb.append('\n'), e); + } + } + if (isGraalFrame) { + remainingGraalFrames--; + } + } + String context = sb.toString(); + if (SampleBytes) { + scope.bytesPerGraalContext(context).add((int) size); + } + if (SampleInstances) { + scope.instancesPerGraalContext(context).inc(); + } + } + } + + protected StringBuilder append(StringBuilder sb, StackTraceElement e) { + String className = e.getClassName(); + int period = className.lastIndexOf('.'); + if (period != -1) { + sb.append(className, period + 1, className.length()); + } else { + sb.append(className); + } + sb.append('.').append(e.getMethodName()); + if (e.isNativeMethod()) { + sb.append("(Native Method)"); + } else if (e.getFileName() != null && e.getLineNumber() >= 0) { + sb.append('(').append(e.getFileName()).append(':').append(e.getLineNumber()).append(")"); + } else { + sb.append("(Unknown Source)"); + } + return sb; + } + } + + /** + * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places + * values with higher frequencies first. + */ + static class CountedValue implements Comparable { + + private int count; + private final Object value; + + public CountedValue(int count, Object value) { + this.count = count; + this.value = value; + } + + public int compareTo(CountedValue o) { + if (count < o.count) { + return 1; + } else if (count > o.count) { + return -1; + } + return 0; + } + + @Override + public String toString() { + return count + " -> " + value; + } + + public void inc() { + count++; + } + + public void add(int n) { + count += n; + } + + public int getCount() { + return count; + } + + public Object getValue() { + return value; + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -321,6 +321,7 @@ Assumptions assumptions = new Assumptions(false); HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true); + canonicalizer.apply(graph, context); new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); if (loopPeeling) { new LoopTransformHighPhase().apply(graph); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java Sun Mar 30 16:08:33 2014 +0200 @@ -158,6 +158,7 @@ new VerifyUsageWithEquals(JavaType.class).apply(graph, context); new VerifyUsageWithEquals(JavaMethod.class).apply(graph, context); new VerifyUsageWithEquals(JavaField.class).apply(graph, context); + new VerifyDebugUsage().apply(graph, context); } private static boolean matches(String[] filters, String s) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -130,7 +130,7 @@ @Before public void beforeTest() { assert debugScope == null; - debugScope = Debug.scope(getClass().getSimpleName()); + debugScope = Debug.scope(getClass()); } @After @@ -498,10 +498,9 @@ } private CompilationResult compileBaseline(ResolvedJavaMethod javaMethod) { - try (Scope bds = Debug.scope("compileBaseline")) { + try (Scope bds = Debug.scope("CompileBaseline", javaMethod, providers.getCodeCache())) { BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess()); - baselineCompiler.generate(javaMethod, -1); - return null; + return baselineCompiler.generate(javaMethod, -1, getBackend(), new CompilationResult(), javaMethod, CompilationResultBuilderFactory.Default); } catch (Throwable e) { throw Debug.handle(e); } @@ -630,7 +629,7 @@ final int id = compilationId.incrementAndGet(); InstalledCode installedCode = null; - try (Scope ds = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) { + try (AllocSpy spy = AllocSpy.open(method); Scope ds = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) { final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); if (printCompilation) { TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s ...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature())); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfReorderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfReorderTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test; + +import java.io.*; +import java.util.*; + +import org.junit.*; + +public class IfReorderTest extends GraalCompilerTest { + + private static Object fieldA = Integer.class; + private static Object fieldB = Double.class; + + @Test + public void test1() { + test("test1Snippet", new ArrayList<>()); + } + + public static Object test1Snippet(Object o) { + /* + * Serializable and List are not mutually exclusive, so these two IFs should never be + * reordered. + */ + if (branchProbability(0.1, o instanceof Serializable)) { + return fieldA; + } + if (branchProbability(0.9, o instanceof List)) { + return fieldB; + } + return null; + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test; + +import org.junit.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; + +public class IntegerEqualsCanonicalizerTest extends GraalCompilerTest { + + @Test + public void testShiftEquals() { + /* + * tests the canonicalization of (x >>> const) == 0 to x |test| (-1 << const) + */ + test("testShiftEqualsSnippet", "testShiftEqualsReference"); + } + + @SuppressWarnings("unused") private static int field; + + public static void testShiftEqualsSnippet(int x, int[] array, int y) { + // optimize + field = (x >>> 10) == 0 ? 1 : 0; + field = (array.length >> 10) == 0 ? 1 : 0; + field = (x << 10) == 0 ? 1 : 0; + // don't optimize + field = (x >> 10) == 0 ? 1 : 0; + field = (x >>> y) == 0 ? 1 : 0; + field = (x >> y) == 0 ? 1 : 0; + field = (x << y) == 0 ? 1 : 0; + field = (x >>> y) == 1 ? 1 : 0; + field = (x >> y) == 1 ? 1 : 0; + field = (x << y) == 1 ? 1 : 0; + } + + public static void testShiftEqualsReference(int x, int[] array, int y) { + field = (x & 0xfffffc00) == 0 ? 1 : 0; + field = (array.length & 0xfffffc00) == 0 ? 1 : 0; + field = (x & 0x3fffff) == 0 ? 1 : 0; + // don't optimize signed right shifts + field = (x >> 10) == 0 ? 1 : 0; + // don't optimize no-constant shift amounts + field = (x >>> y) == 0 ? 1 : 0; + field = (x >> y) == 0 ? 1 : 0; + field = (x << y) == 0 ? 1 : 0; + // don't optimize non-zero comparisons + field = (x >>> y) == 1 ? 1 : 0; + field = (x >> y) == 1 ? 1 : 0; + field = (x << y) == 1 ? 1 : 0; + } + + @Test + public void testCompare() { + test("testCompareSnippet", "testCompareReference"); + } + + public static void testCompareSnippet(int x, int y, int[] array1, int[] array2) { + int tempX = x; + int array1Length = array1.length; + int array2Length = array2.length; + // optimize + field = x == tempX ? 1 : 0; + field = x != tempX ? 1 : 0; + field = array1Length != (-1 - array2Length) ? 1 : 0; + field = array1Length == (-1 - array2Length) ? 1 : 0; + // don't optimize + field = x == y ? 1 : 0; + field = array1Length == array2Length ? 1 : 0; + field = array1Length == (-array2Length) ? 1 : 0; + } + + public static void testCompareReference(int x, int y, int[] array1, int[] array2) { + int array1Length = array1.length; + int array2Length = array2.length; + // optimize + field = 1; + field = 0; + field = 1; + field = 0; + // don't optimize (overlapping value ranges) + field = x == y ? 1 : 0; + field = array1Length == array2Length ? 1 : 0; + field = array1Length == (-array2Length) ? 1 : 0; + } + + private void test(String snippet, String referenceSnippet) { + StructuredGraph graph = getCanonicalizedGraph(snippet); + StructuredGraph referenceGraph = getCanonicalizedGraph(referenceSnippet); + assertEquals(referenceGraph, graph); + } + + private StructuredGraph getCanonicalizedGraph(String snippet) { + StructuredGraph graph = parse(snippet); + new CanonicalizerPhase(false).apply(graph, new PhaseContext(getProviders(), null)); + for (FrameState state : graph.getNodes(FrameState.class).snapshot()) { + state.replaceAtUsages(null); + state.safeDelete(); + } + return graph; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryArithmeticTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryArithmeticTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,4333 @@ +/* + * 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.compiler.test; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; + +public class MemoryArithmeticTest extends GraalCompilerTest { + + @Override + protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) { + return super.getCode(method, graph, true); + } + + /** + * Called before a test is executed. + */ + @Override + protected void before(Method method) { + // don't let any null exception tracking change the generated code. + getMetaAccess().lookupJavaMethod(method).reprofile(); + } + + /** + * A dummy field used by some tests to create side effects. + */ + protected static int count; + + static class FieldObject { + boolean booleanValue; + byte byteValue; + short shortValue; + char charValue; + int intValue; + float floatValue; + long longValue; + double doubleValue; + Object objectValue; + } + + static FieldObject maxObject = new FieldObject(); + static FieldObject minObject; + + static final boolean booleanTestValue1 = false; + static final byte byteTestValue1 = 0; + static final short shortTestValue1 = 0; + static final char charTestValue1 = 0; + static final int intTestValue1 = 0; + static final float floatTestValue1 = 0; + static final long longTestValue1 = 0; + static final double doubleTestValue1 = 0; + static final Object objectTestValue1 = null; + + static final boolean booleanTestValue2 = true; + static final byte byteTestValue2 = Byte.MAX_VALUE; + static final short shortTestValue2 = Short.MAX_VALUE; + static final char charTestValue2 = Character.MAX_VALUE; + static final int intTestValue2 = Integer.MAX_VALUE; + static final float floatTestValue2 = Float.MAX_VALUE; + static final long longTestValue2 = Long.MAX_VALUE; + static final double doubleTestValue2 = Double.MAX_VALUE; + static final Object objectTestValue2 = "String"; + + static { + maxObject.booleanValue = true; + maxObject.byteValue = Byte.MAX_VALUE; + maxObject.shortValue = Short.MAX_VALUE; + maxObject.charValue = Character.MAX_VALUE; + maxObject.intValue = Integer.MAX_VALUE; + maxObject.floatValue = Float.MAX_VALUE; + maxObject.longValue = Long.MAX_VALUE; + maxObject.doubleValue = Double.MAX_VALUE; + maxObject.objectValue = "String"; + } + + public static Object testBooleanCompare(FieldObject f, boolean booleanValue) { + if (f.booleanValue == booleanValue) { + return f; + } + return null; + } + + public static Object testBooleanCompareConstant1(FieldObject f) { + if (f.booleanValue == booleanTestValue1) { + return f; + } + return null; + } + + public static Object testBooleanCompareConstant2(FieldObject f) { + if (f.booleanValue == booleanTestValue2) { + return f; + } + return null; + } + + @Test + public void testBooleanCompares() { + FieldObject f = new FieldObject(); + test("testBooleanCompare", f, booleanTestValue1); + test("testBooleanCompareConstant1", f); + test("testBooleanCompareConstant2", f); + } + + @Test + public void testBooleanNullCompares() { + test("testBooleanCompare", null, booleanTestValue1); + } + + @Test + public void testBooleanNullCompares1() { + test("testBooleanCompareConstant1", (Object) null); + } + + @Test + public void testBooleanNullCompares2() { + test("testBooleanCompareConstant2", (Object) null); + } + + public static Object testByteCompare(FieldObject f, byte byteValue) { + if (f.byteValue == byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareConstant1(FieldObject f) { + if (f.byteValue == byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareConstant2(FieldObject f) { + if (f.byteValue == byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteCompares() { + FieldObject f = new FieldObject(); + test("testByteCompare", f, byteTestValue1); + test("testByteCompareConstant1", f); + test("testByteCompareConstant2", f); + } + + @Test + public void testByteNullCompares() { + test("testByteCompare", null, byteTestValue1); + } + + @Test + public void testByteNullCompares1() { + test("testByteCompareConstant1", (Object) null); + } + + @Test + public void testByteNullCompares2() { + test("testByteCompareConstant2", (Object) null); + } + + public static Object testByteCompareLess(FieldObject f, byte byteValue) { + if (f.byteValue < byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareLessConstant1(FieldObject f) { + if (f.byteValue < byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareLessConstant2(FieldObject f) { + if (f.byteValue < byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesLess() { + FieldObject f = new FieldObject(); + test("testByteCompareLess", f, byteTestValue1); + test("testByteCompareLessConstant1", f); + test("testByteCompareLessConstant2", f); + } + + @Test + public void testByteNullComparesLess() { + test("testByteCompareLess", null, byteTestValue1); + } + + @Test + public void testByteNullComparesLess1() { + test("testByteCompareLessConstant1", (Object) null); + } + + @Test + public void testByteNullComparesLess2() { + test("testByteCompareLessConstant2", (Object) null); + } + + public static Object testByteSwappedCompareLess(FieldObject f, byte byteValue) { + if (byteValue < f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessConstant1(FieldObject f) { + if (byteTestValue1 < f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessConstant2(FieldObject f) { + if (byteTestValue2 < f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareLess", f, byteTestValue1); + test("testByteSwappedCompareLessConstant1", f); + test("testByteSwappedCompareLessConstant2", f); + } + + @Test + public void testByteNullSwappedComparesLess() { + test("testByteSwappedCompareLess", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesLess1() { + test("testByteSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesLess2() { + test("testByteSwappedCompareLessConstant2", (Object) null); + } + + public static Object testByteCompareLessEqual(FieldObject f, byte byteValue) { + if (f.byteValue <= byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareLessEqualConstant1(FieldObject f) { + if (f.byteValue <= byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareLessEqualConstant2(FieldObject f) { + if (f.byteValue <= byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testByteCompareLessEqual", f, byteTestValue1); + test("testByteCompareLessEqualConstant1", f); + test("testByteCompareLessEqualConstant2", f); + } + + @Test + public void testByteNullComparesLessEqual() { + test("testByteCompareLessEqual", null, byteTestValue1); + } + + @Test + public void testByteNullComparesLessEqual1() { + test("testByteCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testByteNullComparesLessEqual2() { + test("testByteCompareLessEqualConstant2", (Object) null); + } + + public static Object testByteSwappedCompareLessEqual(FieldObject f, byte byteValue) { + if (byteValue <= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessEqualConstant1(FieldObject f) { + if (byteTestValue1 <= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareLessEqualConstant2(FieldObject f) { + if (byteTestValue2 <= f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareLessEqual", f, byteTestValue1); + test("testByteSwappedCompareLessEqualConstant1", f); + test("testByteSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testByteNullSwappedComparesLessEqual() { + test("testByteSwappedCompareLessEqual", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesLessEqual1() { + test("testByteSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesLessEqual2() { + test("testByteSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testByteCompareGreater(FieldObject f, byte byteValue) { + if (f.byteValue > byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterConstant1(FieldObject f) { + if (f.byteValue > byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterConstant2(FieldObject f) { + if (f.byteValue > byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesGreater() { + FieldObject f = new FieldObject(); + test("testByteCompareGreater", f, byteTestValue1); + test("testByteCompareGreaterConstant1", f); + test("testByteCompareGreaterConstant2", f); + } + + @Test + public void testByteNullComparesGreater() { + test("testByteCompareGreater", null, byteTestValue1); + } + + @Test + public void testByteNullComparesGreater1() { + test("testByteCompareGreaterConstant1", (Object) null); + } + + @Test + public void testByteNullComparesGreater2() { + test("testByteCompareGreaterConstant2", (Object) null); + } + + public static Object testByteSwappedCompareGreater(FieldObject f, byte byteValue) { + if (byteValue > f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterConstant1(FieldObject f) { + if (byteTestValue1 > f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterConstant2(FieldObject f) { + if (byteTestValue2 > f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareGreater", f, byteTestValue1); + test("testByteSwappedCompareGreaterConstant1", f); + test("testByteSwappedCompareGreaterConstant2", f); + } + + @Test + public void testByteNullSwappedComparesGreater() { + test("testByteSwappedCompareGreater", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesGreater1() { + test("testByteSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesGreater2() { + test("testByteSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testByteCompareGreaterEqual(FieldObject f, byte byteValue) { + if (f.byteValue >= byteValue) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterEqualConstant1(FieldObject f) { + if (f.byteValue >= byteTestValue1) { + return f; + } + return null; + } + + public static Object testByteCompareGreaterEqualConstant2(FieldObject f) { + if (f.byteValue >= byteTestValue2) { + return f; + } + return null; + } + + @Test + public void testByteComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testByteCompareGreaterEqual", f, byteTestValue1); + test("testByteCompareGreaterEqualConstant1", f); + test("testByteCompareGreaterEqualConstant2", f); + } + + @Test + public void testByteNullComparesGreaterEqual() { + test("testByteCompareGreaterEqual", null, byteTestValue1); + } + + @Test + public void testByteNullComparesGreaterEqual1() { + test("testByteCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testByteNullComparesGreaterEqual2() { + test("testByteCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testByteSwappedCompareGreaterEqual(FieldObject f, byte byteValue) { + if (byteValue >= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (byteTestValue1 >= f.byteValue) { + return f; + } + return null; + } + + public static Object testByteSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (byteTestValue2 >= f.byteValue) { + return f; + } + return null; + } + + @Test + public void testByteSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testByteSwappedCompareGreaterEqual", f, byteTestValue1); + test("testByteSwappedCompareGreaterEqualConstant1", f); + test("testByteSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testByteNullSwappedComparesGreaterEqual() { + test("testByteSwappedCompareGreaterEqual", null, byteTestValue1); + } + + @Test + public void testByteNullSwappedComparesGreaterEqual1() { + test("testByteSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testByteNullSwappedComparesGreaterEqual2() { + test("testByteSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testShortCompare(FieldObject f, short shortValue) { + if (f.shortValue == shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareConstant1(FieldObject f) { + if (f.shortValue == shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareConstant2(FieldObject f) { + if (f.shortValue == shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortCompares() { + FieldObject f = new FieldObject(); + test("testShortCompare", f, shortTestValue1); + test("testShortCompareConstant1", f); + test("testShortCompareConstant2", f); + } + + @Test + public void testShortNullCompares() { + test("testShortCompare", null, shortTestValue1); + } + + @Test + public void testShortNullCompares1() { + test("testShortCompareConstant1", (Object) null); + } + + @Test + public void testShortNullCompares2() { + test("testShortCompareConstant2", (Object) null); + } + + public static Object testShortCompareLess(FieldObject f, short shortValue) { + if (f.shortValue < shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareLessConstant1(FieldObject f) { + if (f.shortValue < shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareLessConstant2(FieldObject f) { + if (f.shortValue < shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesLess() { + FieldObject f = new FieldObject(); + test("testShortCompareLess", f, shortTestValue1); + test("testShortCompareLessConstant1", f); + test("testShortCompareLessConstant2", f); + } + + @Test + public void testShortNullComparesLess() { + test("testShortCompareLess", null, shortTestValue1); + } + + @Test + public void testShortNullComparesLess1() { + test("testShortCompareLessConstant1", (Object) null); + } + + @Test + public void testShortNullComparesLess2() { + test("testShortCompareLessConstant2", (Object) null); + } + + public static Object testShortSwappedCompareLess(FieldObject f, short shortValue) { + if (shortValue < f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessConstant1(FieldObject f) { + if (shortTestValue1 < f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessConstant2(FieldObject f) { + if (shortTestValue2 < f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareLess", f, shortTestValue1); + test("testShortSwappedCompareLessConstant1", f); + test("testShortSwappedCompareLessConstant2", f); + } + + @Test + public void testShortNullSwappedComparesLess() { + test("testShortSwappedCompareLess", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesLess1() { + test("testShortSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesLess2() { + test("testShortSwappedCompareLessConstant2", (Object) null); + } + + public static Object testShortCompareLessEqual(FieldObject f, short shortValue) { + if (f.shortValue <= shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareLessEqualConstant1(FieldObject f) { + if (f.shortValue <= shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareLessEqualConstant2(FieldObject f) { + if (f.shortValue <= shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testShortCompareLessEqual", f, shortTestValue1); + test("testShortCompareLessEqualConstant1", f); + test("testShortCompareLessEqualConstant2", f); + } + + @Test + public void testShortNullComparesLessEqual() { + test("testShortCompareLessEqual", null, shortTestValue1); + } + + @Test + public void testShortNullComparesLessEqual1() { + test("testShortCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testShortNullComparesLessEqual2() { + test("testShortCompareLessEqualConstant2", (Object) null); + } + + public static Object testShortSwappedCompareLessEqual(FieldObject f, short shortValue) { + if (shortValue <= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessEqualConstant1(FieldObject f) { + if (shortTestValue1 <= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareLessEqualConstant2(FieldObject f) { + if (shortTestValue2 <= f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareLessEqual", f, shortTestValue1); + test("testShortSwappedCompareLessEqualConstant1", f); + test("testShortSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testShortNullSwappedComparesLessEqual() { + test("testShortSwappedCompareLessEqual", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesLessEqual1() { + test("testShortSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesLessEqual2() { + test("testShortSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testShortCompareGreater(FieldObject f, short shortValue) { + if (f.shortValue > shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterConstant1(FieldObject f) { + if (f.shortValue > shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterConstant2(FieldObject f) { + if (f.shortValue > shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesGreater() { + FieldObject f = new FieldObject(); + test("testShortCompareGreater", f, shortTestValue1); + test("testShortCompareGreaterConstant1", f); + test("testShortCompareGreaterConstant2", f); + } + + @Test + public void testShortNullComparesGreater() { + test("testShortCompareGreater", null, shortTestValue1); + } + + @Test + public void testShortNullComparesGreater1() { + test("testShortCompareGreaterConstant1", (Object) null); + } + + @Test + public void testShortNullComparesGreater2() { + test("testShortCompareGreaterConstant2", (Object) null); + } + + public static Object testShortSwappedCompareGreater(FieldObject f, short shortValue) { + if (shortValue > f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterConstant1(FieldObject f) { + if (shortTestValue1 > f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterConstant2(FieldObject f) { + if (shortTestValue2 > f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareGreater", f, shortTestValue1); + test("testShortSwappedCompareGreaterConstant1", f); + test("testShortSwappedCompareGreaterConstant2", f); + } + + @Test + public void testShortNullSwappedComparesGreater() { + test("testShortSwappedCompareGreater", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesGreater1() { + test("testShortSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesGreater2() { + test("testShortSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testShortCompareGreaterEqual(FieldObject f, short shortValue) { + if (f.shortValue >= shortValue) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterEqualConstant1(FieldObject f) { + if (f.shortValue >= shortTestValue1) { + return f; + } + return null; + } + + public static Object testShortCompareGreaterEqualConstant2(FieldObject f) { + if (f.shortValue >= shortTestValue2) { + return f; + } + return null; + } + + @Test + public void testShortComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testShortCompareGreaterEqual", f, shortTestValue1); + test("testShortCompareGreaterEqualConstant1", f); + test("testShortCompareGreaterEqualConstant2", f); + } + + @Test + public void testShortNullComparesGreaterEqual() { + test("testShortCompareGreaterEqual", null, shortTestValue1); + } + + @Test + public void testShortNullComparesGreaterEqual1() { + test("testShortCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testShortNullComparesGreaterEqual2() { + test("testShortCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testShortSwappedCompareGreaterEqual(FieldObject f, short shortValue) { + if (shortValue >= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (shortTestValue1 >= f.shortValue) { + return f; + } + return null; + } + + public static Object testShortSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (shortTestValue2 >= f.shortValue) { + return f; + } + return null; + } + + @Test + public void testShortSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testShortSwappedCompareGreaterEqual", f, shortTestValue1); + test("testShortSwappedCompareGreaterEqualConstant1", f); + test("testShortSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testShortNullSwappedComparesGreaterEqual() { + test("testShortSwappedCompareGreaterEqual", null, shortTestValue1); + } + + @Test + public void testShortNullSwappedComparesGreaterEqual1() { + test("testShortSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testShortNullSwappedComparesGreaterEqual2() { + test("testShortSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testCharCompare(FieldObject f, char charValue) { + if (f.charValue == charValue) { + return f; + } + return null; + } + + public static Object testCharCompareConstant1(FieldObject f) { + if (f.charValue == charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareConstant2(FieldObject f) { + if (f.charValue == charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharCompares() { + FieldObject f = new FieldObject(); + test("testCharCompare", f, charTestValue1); + test("testCharCompareConstant1", f); + test("testCharCompareConstant2", f); + } + + @Test + public void testCharNullCompares() { + test("testCharCompare", null, charTestValue1); + } + + @Test + public void testCharNullCompares1() { + test("testCharCompareConstant1", (Object) null); + } + + @Test + public void testCharNullCompares2() { + test("testCharCompareConstant2", (Object) null); + } + + public static Object testCharCompareLess(FieldObject f, char charValue) { + if (f.charValue < charValue) { + return f; + } + return null; + } + + public static Object testCharCompareLessConstant1(FieldObject f) { + if (f.charValue < charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareLessConstant2(FieldObject f) { + if (f.charValue < charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesLess() { + FieldObject f = new FieldObject(); + test("testCharCompareLess", f, charTestValue1); + test("testCharCompareLessConstant1", f); + test("testCharCompareLessConstant2", f); + } + + @Test + public void testCharNullComparesLess() { + test("testCharCompareLess", null, charTestValue1); + } + + @Test + public void testCharNullComparesLess1() { + test("testCharCompareLessConstant1", (Object) null); + } + + @Test + public void testCharNullComparesLess2() { + test("testCharCompareLessConstant2", (Object) null); + } + + public static Object testCharSwappedCompareLess(FieldObject f, char charValue) { + if (charValue < f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessConstant1(FieldObject f) { + if (charTestValue1 < f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessConstant2(FieldObject f) { + if (charTestValue2 < f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareLess", f, charTestValue1); + test("testCharSwappedCompareLessConstant1", f); + test("testCharSwappedCompareLessConstant2", f); + } + + @Test + public void testCharNullSwappedComparesLess() { + test("testCharSwappedCompareLess", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesLess1() { + test("testCharSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesLess2() { + test("testCharSwappedCompareLessConstant2", (Object) null); + } + + public static Object testCharCompareLessEqual(FieldObject f, char charValue) { + if (f.charValue <= charValue) { + return f; + } + return null; + } + + public static Object testCharCompareLessEqualConstant1(FieldObject f) { + if (f.charValue <= charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareLessEqualConstant2(FieldObject f) { + if (f.charValue <= charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testCharCompareLessEqual", f, charTestValue1); + test("testCharCompareLessEqualConstant1", f); + test("testCharCompareLessEqualConstant2", f); + } + + @Test + public void testCharNullComparesLessEqual() { + test("testCharCompareLessEqual", null, charTestValue1); + } + + @Test + public void testCharNullComparesLessEqual1() { + test("testCharCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testCharNullComparesLessEqual2() { + test("testCharCompareLessEqualConstant2", (Object) null); + } + + public static Object testCharSwappedCompareLessEqual(FieldObject f, char charValue) { + if (charValue <= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessEqualConstant1(FieldObject f) { + if (charTestValue1 <= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareLessEqualConstant2(FieldObject f) { + if (charTestValue2 <= f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareLessEqual", f, charTestValue1); + test("testCharSwappedCompareLessEqualConstant1", f); + test("testCharSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testCharNullSwappedComparesLessEqual() { + test("testCharSwappedCompareLessEqual", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesLessEqual1() { + test("testCharSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesLessEqual2() { + test("testCharSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testCharCompareGreater(FieldObject f, char charValue) { + if (f.charValue > charValue) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterConstant1(FieldObject f) { + if (f.charValue > charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterConstant2(FieldObject f) { + if (f.charValue > charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesGreater() { + FieldObject f = new FieldObject(); + test("testCharCompareGreater", f, charTestValue1); + test("testCharCompareGreaterConstant1", f); + test("testCharCompareGreaterConstant2", f); + } + + @Test + public void testCharNullComparesGreater() { + test("testCharCompareGreater", null, charTestValue1); + } + + @Test + public void testCharNullComparesGreater1() { + test("testCharCompareGreaterConstant1", (Object) null); + } + + @Test + public void testCharNullComparesGreater2() { + test("testCharCompareGreaterConstant2", (Object) null); + } + + public static Object testCharSwappedCompareGreater(FieldObject f, char charValue) { + if (charValue > f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterConstant1(FieldObject f) { + if (charTestValue1 > f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterConstant2(FieldObject f) { + if (charTestValue2 > f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareGreater", f, charTestValue1); + test("testCharSwappedCompareGreaterConstant1", f); + test("testCharSwappedCompareGreaterConstant2", f); + } + + @Test + public void testCharNullSwappedComparesGreater() { + test("testCharSwappedCompareGreater", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesGreater1() { + test("testCharSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesGreater2() { + test("testCharSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testCharCompareGreaterEqual(FieldObject f, char charValue) { + if (f.charValue >= charValue) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterEqualConstant1(FieldObject f) { + if (f.charValue >= charTestValue1) { + return f; + } + return null; + } + + public static Object testCharCompareGreaterEqualConstant2(FieldObject f) { + if (f.charValue >= charTestValue2) { + return f; + } + return null; + } + + @Test + public void testCharComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testCharCompareGreaterEqual", f, charTestValue1); + test("testCharCompareGreaterEqualConstant1", f); + test("testCharCompareGreaterEqualConstant2", f); + } + + @Test + public void testCharNullComparesGreaterEqual() { + test("testCharCompareGreaterEqual", null, charTestValue1); + } + + @Test + public void testCharNullComparesGreaterEqual1() { + test("testCharCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testCharNullComparesGreaterEqual2() { + test("testCharCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testCharSwappedCompareGreaterEqual(FieldObject f, char charValue) { + if (charValue >= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (charTestValue1 >= f.charValue) { + return f; + } + return null; + } + + public static Object testCharSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (charTestValue2 >= f.charValue) { + return f; + } + return null; + } + + @Test + public void testCharSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testCharSwappedCompareGreaterEqual", f, charTestValue1); + test("testCharSwappedCompareGreaterEqualConstant1", f); + test("testCharSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testCharNullSwappedComparesGreaterEqual() { + test("testCharSwappedCompareGreaterEqual", null, charTestValue1); + } + + @Test + public void testCharNullSwappedComparesGreaterEqual1() { + test("testCharSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testCharNullSwappedComparesGreaterEqual2() { + test("testCharSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testIntCompare(FieldObject f, int intValue) { + if (f.intValue == intValue) { + return f; + } + return null; + } + + public static Object testIntCompareConstant1(FieldObject f) { + if (f.intValue == intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareConstant2(FieldObject f) { + if (f.intValue == intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntCompares() { + FieldObject f = new FieldObject(); + test("testIntCompare", f, intTestValue1); + test("testIntCompareConstant1", f); + test("testIntCompareConstant2", f); + } + + @Test + public void testIntNullCompares() { + test("testIntCompare", null, intTestValue1); + } + + @Test + public void testIntNullCompares1() { + test("testIntCompareConstant1", (Object) null); + } + + @Test + public void testIntNullCompares2() { + test("testIntCompareConstant2", (Object) null); + } + + public static Object testIntCompareLess(FieldObject f, int intValue) { + if (f.intValue < intValue) { + return f; + } + return null; + } + + public static Object testIntCompareLessConstant1(FieldObject f) { + if (f.intValue < intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareLessConstant2(FieldObject f) { + if (f.intValue < intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesLess() { + FieldObject f = new FieldObject(); + test("testIntCompareLess", f, intTestValue1); + test("testIntCompareLessConstant1", f); + test("testIntCompareLessConstant2", f); + } + + @Test + public void testIntNullComparesLess() { + test("testIntCompareLess", null, intTestValue1); + } + + @Test + public void testIntNullComparesLess1() { + test("testIntCompareLessConstant1", (Object) null); + } + + @Test + public void testIntNullComparesLess2() { + test("testIntCompareLessConstant2", (Object) null); + } + + public static Object testIntSwappedCompareLess(FieldObject f, int intValue) { + if (intValue < f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessConstant1(FieldObject f) { + if (intTestValue1 < f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessConstant2(FieldObject f) { + if (intTestValue2 < f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareLess", f, intTestValue1); + test("testIntSwappedCompareLessConstant1", f); + test("testIntSwappedCompareLessConstant2", f); + } + + @Test + public void testIntNullSwappedComparesLess() { + test("testIntSwappedCompareLess", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesLess1() { + test("testIntSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesLess2() { + test("testIntSwappedCompareLessConstant2", (Object) null); + } + + public static Object testIntCompareLessEqual(FieldObject f, int intValue) { + if (f.intValue <= intValue) { + return f; + } + return null; + } + + public static Object testIntCompareLessEqualConstant1(FieldObject f) { + if (f.intValue <= intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareLessEqualConstant2(FieldObject f) { + if (f.intValue <= intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testIntCompareLessEqual", f, intTestValue1); + test("testIntCompareLessEqualConstant1", f); + test("testIntCompareLessEqualConstant2", f); + } + + @Test + public void testIntNullComparesLessEqual() { + test("testIntCompareLessEqual", null, intTestValue1); + } + + @Test + public void testIntNullComparesLessEqual1() { + test("testIntCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testIntNullComparesLessEqual2() { + test("testIntCompareLessEqualConstant2", (Object) null); + } + + public static Object testIntSwappedCompareLessEqual(FieldObject f, int intValue) { + if (intValue <= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessEqualConstant1(FieldObject f) { + if (intTestValue1 <= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareLessEqualConstant2(FieldObject f) { + if (intTestValue2 <= f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareLessEqual", f, intTestValue1); + test("testIntSwappedCompareLessEqualConstant1", f); + test("testIntSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testIntNullSwappedComparesLessEqual() { + test("testIntSwappedCompareLessEqual", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesLessEqual1() { + test("testIntSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesLessEqual2() { + test("testIntSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testIntCompareGreater(FieldObject f, int intValue) { + if (f.intValue > intValue) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterConstant1(FieldObject f) { + if (f.intValue > intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterConstant2(FieldObject f) { + if (f.intValue > intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesGreater() { + FieldObject f = new FieldObject(); + test("testIntCompareGreater", f, intTestValue1); + test("testIntCompareGreaterConstant1", f); + test("testIntCompareGreaterConstant2", f); + } + + @Test + public void testIntNullComparesGreater() { + test("testIntCompareGreater", null, intTestValue1); + } + + @Test + public void testIntNullComparesGreater1() { + test("testIntCompareGreaterConstant1", (Object) null); + } + + @Test + public void testIntNullComparesGreater2() { + test("testIntCompareGreaterConstant2", (Object) null); + } + + public static Object testIntSwappedCompareGreater(FieldObject f, int intValue) { + if (intValue > f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterConstant1(FieldObject f) { + if (intTestValue1 > f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterConstant2(FieldObject f) { + if (intTestValue2 > f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareGreater", f, intTestValue1); + test("testIntSwappedCompareGreaterConstant1", f); + test("testIntSwappedCompareGreaterConstant2", f); + } + + @Test + public void testIntNullSwappedComparesGreater() { + test("testIntSwappedCompareGreater", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesGreater1() { + test("testIntSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesGreater2() { + test("testIntSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testIntCompareGreaterEqual(FieldObject f, int intValue) { + if (f.intValue >= intValue) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterEqualConstant1(FieldObject f) { + if (f.intValue >= intTestValue1) { + return f; + } + return null; + } + + public static Object testIntCompareGreaterEqualConstant2(FieldObject f) { + if (f.intValue >= intTestValue2) { + return f; + } + return null; + } + + @Test + public void testIntComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testIntCompareGreaterEqual", f, intTestValue1); + test("testIntCompareGreaterEqualConstant1", f); + test("testIntCompareGreaterEqualConstant2", f); + } + + @Test + public void testIntNullComparesGreaterEqual() { + test("testIntCompareGreaterEqual", null, intTestValue1); + } + + @Test + public void testIntNullComparesGreaterEqual1() { + test("testIntCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testIntNullComparesGreaterEqual2() { + test("testIntCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testIntSwappedCompareGreaterEqual(FieldObject f, int intValue) { + if (intValue >= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (intTestValue1 >= f.intValue) { + return f; + } + return null; + } + + public static Object testIntSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (intTestValue2 >= f.intValue) { + return f; + } + return null; + } + + @Test + public void testIntSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testIntSwappedCompareGreaterEqual", f, intTestValue1); + test("testIntSwappedCompareGreaterEqualConstant1", f); + test("testIntSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testIntNullSwappedComparesGreaterEqual() { + test("testIntSwappedCompareGreaterEqual", null, intTestValue1); + } + + @Test + public void testIntNullSwappedComparesGreaterEqual1() { + test("testIntSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testIntNullSwappedComparesGreaterEqual2() { + test("testIntSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testFloatCompare(FieldObject f, float floatValue) { + if (f.floatValue == floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareConstant1(FieldObject f) { + if (f.floatValue == floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareConstant2(FieldObject f) { + if (f.floatValue == floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatCompares() { + FieldObject f = new FieldObject(); + test("testFloatCompare", f, floatTestValue1); + test("testFloatCompareConstant1", f); + test("testFloatCompareConstant2", f); + } + + @Test + public void testFloatNullCompares() { + test("testFloatCompare", null, floatTestValue1); + } + + @Test + public void testFloatNullCompares1() { + test("testFloatCompareConstant1", (Object) null); + } + + @Test + public void testFloatNullCompares2() { + test("testFloatCompareConstant2", (Object) null); + } + + public static Object testFloatCompareLess(FieldObject f, float floatValue) { + if (f.floatValue < floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareLessConstant1(FieldObject f) { + if (f.floatValue < floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareLessConstant2(FieldObject f) { + if (f.floatValue < floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesLess() { + FieldObject f = new FieldObject(); + test("testFloatCompareLess", f, floatTestValue1); + test("testFloatCompareLessConstant1", f); + test("testFloatCompareLessConstant2", f); + } + + @Test + public void testFloatNullComparesLess() { + test("testFloatCompareLess", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesLess1() { + test("testFloatCompareLessConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesLess2() { + test("testFloatCompareLessConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareLess(FieldObject f, float floatValue) { + if (floatValue < f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessConstant1(FieldObject f) { + if (floatTestValue1 < f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessConstant2(FieldObject f) { + if (floatTestValue2 < f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareLess", f, floatTestValue1); + test("testFloatSwappedCompareLessConstant1", f); + test("testFloatSwappedCompareLessConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesLess() { + test("testFloatSwappedCompareLess", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesLess1() { + test("testFloatSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesLess2() { + test("testFloatSwappedCompareLessConstant2", (Object) null); + } + + public static Object testFloatCompareLessEqual(FieldObject f, float floatValue) { + if (f.floatValue <= floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareLessEqualConstant1(FieldObject f) { + if (f.floatValue <= floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareLessEqualConstant2(FieldObject f) { + if (f.floatValue <= floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testFloatCompareLessEqual", f, floatTestValue1); + test("testFloatCompareLessEqualConstant1", f); + test("testFloatCompareLessEqualConstant2", f); + } + + @Test + public void testFloatNullComparesLessEqual() { + test("testFloatCompareLessEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesLessEqual1() { + test("testFloatCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesLessEqual2() { + test("testFloatCompareLessEqualConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareLessEqual(FieldObject f, float floatValue) { + if (floatValue <= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessEqualConstant1(FieldObject f) { + if (floatTestValue1 <= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareLessEqualConstant2(FieldObject f) { + if (floatTestValue2 <= f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareLessEqual", f, floatTestValue1); + test("testFloatSwappedCompareLessEqualConstant1", f); + test("testFloatSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesLessEqual() { + test("testFloatSwappedCompareLessEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesLessEqual1() { + test("testFloatSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesLessEqual2() { + test("testFloatSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testFloatCompareGreater(FieldObject f, float floatValue) { + if (f.floatValue > floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterConstant1(FieldObject f) { + if (f.floatValue > floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterConstant2(FieldObject f) { + if (f.floatValue > floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesGreater() { + FieldObject f = new FieldObject(); + test("testFloatCompareGreater", f, floatTestValue1); + test("testFloatCompareGreaterConstant1", f); + test("testFloatCompareGreaterConstant2", f); + } + + @Test + public void testFloatNullComparesGreater() { + test("testFloatCompareGreater", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesGreater1() { + test("testFloatCompareGreaterConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesGreater2() { + test("testFloatCompareGreaterConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareGreater(FieldObject f, float floatValue) { + if (floatValue > f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterConstant1(FieldObject f) { + if (floatTestValue1 > f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterConstant2(FieldObject f) { + if (floatTestValue2 > f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareGreater", f, floatTestValue1); + test("testFloatSwappedCompareGreaterConstant1", f); + test("testFloatSwappedCompareGreaterConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesGreater() { + test("testFloatSwappedCompareGreater", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesGreater1() { + test("testFloatSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesGreater2() { + test("testFloatSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testFloatCompareGreaterEqual(FieldObject f, float floatValue) { + if (f.floatValue >= floatValue) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterEqualConstant1(FieldObject f) { + if (f.floatValue >= floatTestValue1) { + return f; + } + return null; + } + + public static Object testFloatCompareGreaterEqualConstant2(FieldObject f) { + if (f.floatValue >= floatTestValue2) { + return f; + } + return null; + } + + @Test + public void testFloatComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testFloatCompareGreaterEqual", f, floatTestValue1); + test("testFloatCompareGreaterEqualConstant1", f); + test("testFloatCompareGreaterEqualConstant2", f); + } + + @Test + public void testFloatNullComparesGreaterEqual() { + test("testFloatCompareGreaterEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullComparesGreaterEqual1() { + test("testFloatCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullComparesGreaterEqual2() { + test("testFloatCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testFloatSwappedCompareGreaterEqual(FieldObject f, float floatValue) { + if (floatValue >= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (floatTestValue1 >= f.floatValue) { + return f; + } + return null; + } + + public static Object testFloatSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (floatTestValue2 >= f.floatValue) { + return f; + } + return null; + } + + @Test + public void testFloatSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testFloatSwappedCompareGreaterEqual", f, floatTestValue1); + test("testFloatSwappedCompareGreaterEqualConstant1", f); + test("testFloatSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testFloatNullSwappedComparesGreaterEqual() { + test("testFloatSwappedCompareGreaterEqual", null, floatTestValue1); + } + + @Test + public void testFloatNullSwappedComparesGreaterEqual1() { + test("testFloatSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testFloatNullSwappedComparesGreaterEqual2() { + test("testFloatSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testLongCompare(FieldObject f, long longValue) { + if (f.longValue == longValue) { + return f; + } + return null; + } + + public static Object testLongCompareConstant1(FieldObject f) { + if (f.longValue == longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareConstant2(FieldObject f) { + if (f.longValue == longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongCompares() { + FieldObject f = new FieldObject(); + test("testLongCompare", f, longTestValue1); + test("testLongCompareConstant1", f); + test("testLongCompareConstant2", f); + } + + @Test + public void testLongNullCompares() { + test("testLongCompare", null, longTestValue1); + } + + @Test + public void testLongNullCompares1() { + test("testLongCompareConstant1", (Object) null); + } + + @Test + public void testLongNullCompares2() { + test("testLongCompareConstant2", (Object) null); + } + + public static Object testLongCompareLess(FieldObject f, long longValue) { + if (f.longValue < longValue) { + return f; + } + return null; + } + + public static Object testLongCompareLessConstant1(FieldObject f) { + if (f.longValue < longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareLessConstant2(FieldObject f) { + if (f.longValue < longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesLess() { + FieldObject f = new FieldObject(); + test("testLongCompareLess", f, longTestValue1); + test("testLongCompareLessConstant1", f); + test("testLongCompareLessConstant2", f); + } + + @Test + public void testLongNullComparesLess() { + test("testLongCompareLess", null, longTestValue1); + } + + @Test + public void testLongNullComparesLess1() { + test("testLongCompareLessConstant1", (Object) null); + } + + @Test + public void testLongNullComparesLess2() { + test("testLongCompareLessConstant2", (Object) null); + } + + public static Object testLongSwappedCompareLess(FieldObject f, long longValue) { + if (longValue < f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessConstant1(FieldObject f) { + if (longTestValue1 < f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessConstant2(FieldObject f) { + if (longTestValue2 < f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareLess", f, longTestValue1); + test("testLongSwappedCompareLessConstant1", f); + test("testLongSwappedCompareLessConstant2", f); + } + + @Test + public void testLongNullSwappedComparesLess() { + test("testLongSwappedCompareLess", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesLess1() { + test("testLongSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesLess2() { + test("testLongSwappedCompareLessConstant2", (Object) null); + } + + public static Object testLongCompareLessEqual(FieldObject f, long longValue) { + if (f.longValue <= longValue) { + return f; + } + return null; + } + + public static Object testLongCompareLessEqualConstant1(FieldObject f) { + if (f.longValue <= longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareLessEqualConstant2(FieldObject f) { + if (f.longValue <= longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testLongCompareLessEqual", f, longTestValue1); + test("testLongCompareLessEqualConstant1", f); + test("testLongCompareLessEqualConstant2", f); + } + + @Test + public void testLongNullComparesLessEqual() { + test("testLongCompareLessEqual", null, longTestValue1); + } + + @Test + public void testLongNullComparesLessEqual1() { + test("testLongCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testLongNullComparesLessEqual2() { + test("testLongCompareLessEqualConstant2", (Object) null); + } + + public static Object testLongSwappedCompareLessEqual(FieldObject f, long longValue) { + if (longValue <= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessEqualConstant1(FieldObject f) { + if (longTestValue1 <= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareLessEqualConstant2(FieldObject f) { + if (longTestValue2 <= f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareLessEqual", f, longTestValue1); + test("testLongSwappedCompareLessEqualConstant1", f); + test("testLongSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testLongNullSwappedComparesLessEqual() { + test("testLongSwappedCompareLessEqual", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesLessEqual1() { + test("testLongSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesLessEqual2() { + test("testLongSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testLongCompareGreater(FieldObject f, long longValue) { + if (f.longValue > longValue) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterConstant1(FieldObject f) { + if (f.longValue > longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterConstant2(FieldObject f) { + if (f.longValue > longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesGreater() { + FieldObject f = new FieldObject(); + test("testLongCompareGreater", f, longTestValue1); + test("testLongCompareGreaterConstant1", f); + test("testLongCompareGreaterConstant2", f); + } + + @Test + public void testLongNullComparesGreater() { + test("testLongCompareGreater", null, longTestValue1); + } + + @Test + public void testLongNullComparesGreater1() { + test("testLongCompareGreaterConstant1", (Object) null); + } + + @Test + public void testLongNullComparesGreater2() { + test("testLongCompareGreaterConstant2", (Object) null); + } + + public static Object testLongSwappedCompareGreater(FieldObject f, long longValue) { + if (longValue > f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterConstant1(FieldObject f) { + if (longTestValue1 > f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterConstant2(FieldObject f) { + if (longTestValue2 > f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareGreater", f, longTestValue1); + test("testLongSwappedCompareGreaterConstant1", f); + test("testLongSwappedCompareGreaterConstant2", f); + } + + @Test + public void testLongNullSwappedComparesGreater() { + test("testLongSwappedCompareGreater", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesGreater1() { + test("testLongSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesGreater2() { + test("testLongSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testLongCompareGreaterEqual(FieldObject f, long longValue) { + if (f.longValue >= longValue) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterEqualConstant1(FieldObject f) { + if (f.longValue >= longTestValue1) { + return f; + } + return null; + } + + public static Object testLongCompareGreaterEqualConstant2(FieldObject f) { + if (f.longValue >= longTestValue2) { + return f; + } + return null; + } + + @Test + public void testLongComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testLongCompareGreaterEqual", f, longTestValue1); + test("testLongCompareGreaterEqualConstant1", f); + test("testLongCompareGreaterEqualConstant2", f); + } + + @Test + public void testLongNullComparesGreaterEqual() { + test("testLongCompareGreaterEqual", null, longTestValue1); + } + + @Test + public void testLongNullComparesGreaterEqual1() { + test("testLongCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testLongNullComparesGreaterEqual2() { + test("testLongCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testLongSwappedCompareGreaterEqual(FieldObject f, long longValue) { + if (longValue >= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (longTestValue1 >= f.longValue) { + return f; + } + return null; + } + + public static Object testLongSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (longTestValue2 >= f.longValue) { + return f; + } + return null; + } + + @Test + public void testLongSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testLongSwappedCompareGreaterEqual", f, longTestValue1); + test("testLongSwappedCompareGreaterEqualConstant1", f); + test("testLongSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testLongNullSwappedComparesGreaterEqual() { + test("testLongSwappedCompareGreaterEqual", null, longTestValue1); + } + + @Test + public void testLongNullSwappedComparesGreaterEqual1() { + test("testLongSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testLongNullSwappedComparesGreaterEqual2() { + test("testLongSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testDoubleCompare(FieldObject f, double doubleValue) { + if (f.doubleValue == doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareConstant1(FieldObject f) { + if (f.doubleValue == doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareConstant2(FieldObject f) { + if (f.doubleValue == doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleCompares() { + FieldObject f = new FieldObject(); + test("testDoubleCompare", f, doubleTestValue1); + test("testDoubleCompareConstant1", f); + test("testDoubleCompareConstant2", f); + } + + @Test + public void testDoubleNullCompares() { + test("testDoubleCompare", null, doubleTestValue1); + } + + @Test + public void testDoubleNullCompares1() { + test("testDoubleCompareConstant1", (Object) null); + } + + @Test + public void testDoubleNullCompares2() { + test("testDoubleCompareConstant2", (Object) null); + } + + public static Object testDoubleCompareLess(FieldObject f, double doubleValue) { + if (f.doubleValue < doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessConstant1(FieldObject f) { + if (f.doubleValue < doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessConstant2(FieldObject f) { + if (f.doubleValue < doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesLess() { + FieldObject f = new FieldObject(); + test("testDoubleCompareLess", f, doubleTestValue1); + test("testDoubleCompareLessConstant1", f); + test("testDoubleCompareLessConstant2", f); + } + + @Test + public void testDoubleNullComparesLess() { + test("testDoubleCompareLess", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesLess1() { + test("testDoubleCompareLessConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesLess2() { + test("testDoubleCompareLessConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareLess(FieldObject f, double doubleValue) { + if (doubleValue < f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessConstant1(FieldObject f) { + if (doubleTestValue1 < f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessConstant2(FieldObject f) { + if (doubleTestValue2 < f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesLess() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareLess", f, doubleTestValue1); + test("testDoubleSwappedCompareLessConstant1", f); + test("testDoubleSwappedCompareLessConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesLess() { + test("testDoubleSwappedCompareLess", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesLess1() { + test("testDoubleSwappedCompareLessConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesLess2() { + test("testDoubleSwappedCompareLessConstant2", (Object) null); + } + + public static Object testDoubleCompareLessEqual(FieldObject f, double doubleValue) { + if (f.doubleValue <= doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessEqualConstant1(FieldObject f) { + if (f.doubleValue <= doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareLessEqualConstant2(FieldObject f) { + if (f.doubleValue <= doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testDoubleCompareLessEqual", f, doubleTestValue1); + test("testDoubleCompareLessEqualConstant1", f); + test("testDoubleCompareLessEqualConstant2", f); + } + + @Test + public void testDoubleNullComparesLessEqual() { + test("testDoubleCompareLessEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesLessEqual1() { + test("testDoubleCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesLessEqual2() { + test("testDoubleCompareLessEqualConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareLessEqual(FieldObject f, double doubleValue) { + if (doubleValue <= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessEqualConstant1(FieldObject f) { + if (doubleTestValue1 <= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareLessEqualConstant2(FieldObject f) { + if (doubleTestValue2 <= f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesLessEqual() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareLessEqual", f, doubleTestValue1); + test("testDoubleSwappedCompareLessEqualConstant1", f); + test("testDoubleSwappedCompareLessEqualConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesLessEqual() { + test("testDoubleSwappedCompareLessEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesLessEqual1() { + test("testDoubleSwappedCompareLessEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesLessEqual2() { + test("testDoubleSwappedCompareLessEqualConstant2", (Object) null); + } + + public static Object testDoubleCompareGreater(FieldObject f, double doubleValue) { + if (f.doubleValue > doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterConstant1(FieldObject f) { + if (f.doubleValue > doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterConstant2(FieldObject f) { + if (f.doubleValue > doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesGreater() { + FieldObject f = new FieldObject(); + test("testDoubleCompareGreater", f, doubleTestValue1); + test("testDoubleCompareGreaterConstant1", f); + test("testDoubleCompareGreaterConstant2", f); + } + + @Test + public void testDoubleNullComparesGreater() { + test("testDoubleCompareGreater", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesGreater1() { + test("testDoubleCompareGreaterConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesGreater2() { + test("testDoubleCompareGreaterConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareGreater(FieldObject f, double doubleValue) { + if (doubleValue > f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterConstant1(FieldObject f) { + if (doubleTestValue1 > f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterConstant2(FieldObject f) { + if (doubleTestValue2 > f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesGreater() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareGreater", f, doubleTestValue1); + test("testDoubleSwappedCompareGreaterConstant1", f); + test("testDoubleSwappedCompareGreaterConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesGreater() { + test("testDoubleSwappedCompareGreater", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesGreater1() { + test("testDoubleSwappedCompareGreaterConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesGreater2() { + test("testDoubleSwappedCompareGreaterConstant2", (Object) null); + } + + public static Object testDoubleCompareGreaterEqual(FieldObject f, double doubleValue) { + if (f.doubleValue >= doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterEqualConstant1(FieldObject f) { + if (f.doubleValue >= doubleTestValue1) { + return f; + } + return null; + } + + public static Object testDoubleCompareGreaterEqualConstant2(FieldObject f) { + if (f.doubleValue >= doubleTestValue2) { + return f; + } + return null; + } + + @Test + public void testDoubleComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testDoubleCompareGreaterEqual", f, doubleTestValue1); + test("testDoubleCompareGreaterEqualConstant1", f); + test("testDoubleCompareGreaterEqualConstant2", f); + } + + @Test + public void testDoubleNullComparesGreaterEqual() { + test("testDoubleCompareGreaterEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullComparesGreaterEqual1() { + test("testDoubleCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullComparesGreaterEqual2() { + test("testDoubleCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testDoubleSwappedCompareGreaterEqual(FieldObject f, double doubleValue) { + if (doubleValue >= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterEqualConstant1(FieldObject f) { + if (doubleTestValue1 >= f.doubleValue) { + return f; + } + return null; + } + + public static Object testDoubleSwappedCompareGreaterEqualConstant2(FieldObject f) { + if (doubleTestValue2 >= f.doubleValue) { + return f; + } + return null; + } + + @Test + public void testDoubleSwappedComparesGreaterEqual() { + FieldObject f = new FieldObject(); + test("testDoubleSwappedCompareGreaterEqual", f, doubleTestValue1); + test("testDoubleSwappedCompareGreaterEqualConstant1", f); + test("testDoubleSwappedCompareGreaterEqualConstant2", f); + } + + @Test + public void testDoubleNullSwappedComparesGreaterEqual() { + test("testDoubleSwappedCompareGreaterEqual", null, doubleTestValue1); + } + + @Test + public void testDoubleNullSwappedComparesGreaterEqual1() { + test("testDoubleSwappedCompareGreaterEqualConstant1", (Object) null); + } + + @Test + public void testDoubleNullSwappedComparesGreaterEqual2() { + test("testDoubleSwappedCompareGreaterEqualConstant2", (Object) null); + } + + public static Object testObjectCompare(FieldObject f, Object objectValue) { + if (f.objectValue == objectValue) { + return f; + } + return null; + } + + public static Object testObjectCompareConstant1(FieldObject f) { + if (f.objectValue == objectTestValue1) { + return f; + } + return null; + } + + public static Object testObjectCompareConstant2(FieldObject f) { + if (f.objectValue == objectTestValue2) { + return f; + } + return null; + } + + @Test + public void testObjectCompares() { + FieldObject f = new FieldObject(); + test("testObjectCompare", f, objectTestValue1); + test("testObjectCompareConstant1", f); + test("testObjectCompareConstant2", f); + } + + @Test + public void testObjectNullCompares() { + test("testObjectCompare", null, objectTestValue1); + } + + @Test + public void testObjectNullCompares1() { + test("testObjectCompareConstant1", (Object) null); + } + + @Test + public void testObjectNullCompares2() { + test("testObjectCompareConstant2", (Object) null); + } + + public static int testByteAdd(FieldObject f, byte byteValue) { + return f.byteValue + byteValue; + } + + public static int testByteAddConstant1(FieldObject f) { + return f.byteValue + byteTestValue1; + } + + public static int testByteAddConstant2(FieldObject f) { + return f.byteValue + byteTestValue2; + } + + @Test + public void testByteAdds() { + FieldObject f = new FieldObject(); + test("testByteAdd", f, byteTestValue1); + test("testByteAddConstant1", f); + test("testByteAddConstant2", f); + } + + @Test + public void testByteNullAdd() { + test("testByteAdd", null, byteTestValue1); + } + + public static int testShortAdd(FieldObject f, short shortValue) { + return f.shortValue + shortValue; + } + + public static int testShortAddConstant1(FieldObject f) { + return f.shortValue + shortTestValue1; + } + + public static int testShortAddConstant2(FieldObject f) { + return f.shortValue + shortTestValue2; + } + + @Test + public void testShortAdds() { + FieldObject f = new FieldObject(); + test("testShortAdd", f, shortTestValue1); + test("testShortAddConstant1", f); + test("testShortAddConstant2", f); + } + + @Test + public void testShortNullAdd() { + test("testShortAdd", null, shortTestValue1); + } + + public static int testCharAdd(FieldObject f, char charValue) { + return f.charValue + charValue; + } + + public static int testCharAddConstant1(FieldObject f) { + return f.charValue + charTestValue1; + } + + public static int testCharAddConstant2(FieldObject f) { + return f.charValue + charTestValue2; + } + + @Test + public void testCharAdds() { + FieldObject f = new FieldObject(); + test("testCharAdd", f, charTestValue1); + test("testCharAddConstant1", f); + test("testCharAddConstant2", f); + } + + @Test + public void testCharNullAdd() { + test("testCharAdd", null, charTestValue1); + } + + public static int testIntAdd(FieldObject f, int intValue) { + return f.intValue + intValue; + } + + public static int testIntAddConstant1(FieldObject f) { + return f.intValue + intTestValue1; + } + + public static int testIntAddConstant2(FieldObject f) { + return f.intValue + intTestValue2; + } + + @Test + public void testIntAdds() { + FieldObject f = new FieldObject(); + test("testIntAdd", f, intTestValue1); + test("testIntAddConstant1", f); + test("testIntAddConstant2", f); + } + + @Test + public void testIntNullAdd() { + test("testIntAdd", null, intTestValue1); + } + + public static long testLongAdd(FieldObject f, long longValue) { + return f.longValue + longValue; + } + + public static long testLongAddConstant1(FieldObject f) { + return f.longValue + longTestValue1; + } + + public static long testLongAddConstant2(FieldObject f) { + return f.longValue + longTestValue2; + } + + @Test + public void testLongAdds() { + FieldObject f = new FieldObject(); + test("testLongAdd", f, longTestValue1); + test("testLongAddConstant1", f); + test("testLongAddConstant2", f); + } + + @Test + public void testLongNullAdd() { + test("testLongAdd", null, longTestValue1); + } + + public static float testFloatAdd(FieldObject f, float floatValue) { + return f.floatValue + floatValue; + } + + public static float testFloatAddConstant1(FieldObject f) { + return f.floatValue + floatTestValue1; + } + + public static float testFloatAddConstant2(FieldObject f) { + return f.floatValue + floatTestValue2; + } + + @Test + public void testFloatAdds() { + FieldObject f = new FieldObject(); + test("testFloatAdd", f, floatTestValue1); + test("testFloatAddConstant1", f); + test("testFloatAddConstant2", f); + } + + @Test + public void testFloatNullAdd() { + test("testFloatAdd", null, floatTestValue1); + } + + public static double testDoubleAdd(FieldObject f, double doubleValue) { + return f.doubleValue + doubleValue; + } + + public static double testDoubleAddConstant1(FieldObject f) { + return f.doubleValue + doubleTestValue1; + } + + public static double testDoubleAddConstant2(FieldObject f) { + return f.doubleValue + doubleTestValue2; + } + + @Test + public void testDoubleAdds() { + FieldObject f = new FieldObject(); + test("testDoubleAdd", f, doubleTestValue1); + test("testDoubleAddConstant1", f); + test("testDoubleAddConstant2", f); + } + + @Test + public void testDoubleNullAdd() { + test("testDoubleAdd", null, doubleTestValue1); + } + + public static int testByteSub(FieldObject f, byte byteValue) { + return f.byteValue - byteValue; + } + + public static int testByteSubConstant1(FieldObject f) { + return f.byteValue - byteTestValue1; + } + + public static int testByteSubConstant2(FieldObject f) { + return f.byteValue - byteTestValue2; + } + + @Test + public void testByteSubs() { + FieldObject f = new FieldObject(); + test("testByteSub", f, byteTestValue1); + test("testByteSubConstant1", f); + test("testByteSubConstant2", f); + } + + @Test + public void testByteNullSub() { + test("testByteSub", null, byteTestValue1); + } + + public static int testShortSub(FieldObject f, short shortValue) { + return f.shortValue - shortValue; + } + + public static int testShortSubConstant1(FieldObject f) { + return f.shortValue - shortTestValue1; + } + + public static int testShortSubConstant2(FieldObject f) { + return f.shortValue - shortTestValue2; + } + + @Test + public void testShortSubs() { + FieldObject f = new FieldObject(); + test("testShortSub", f, shortTestValue1); + test("testShortSubConstant1", f); + test("testShortSubConstant2", f); + } + + @Test + public void testShortNullSub() { + test("testShortSub", null, shortTestValue1); + } + + public static int testCharSub(FieldObject f, char charValue) { + return f.charValue - charValue; + } + + public static int testCharSubConstant1(FieldObject f) { + return f.charValue - charTestValue1; + } + + public static int testCharSubConstant2(FieldObject f) { + return f.charValue - charTestValue2; + } + + @Test + public void testCharSubs() { + FieldObject f = new FieldObject(); + test("testCharSub", f, charTestValue1); + test("testCharSubConstant1", f); + test("testCharSubConstant2", f); + } + + @Test + public void testCharNullSub() { + test("testCharSub", null, charTestValue1); + } + + public static int testIntSub(FieldObject f, int intValue) { + return f.intValue - intValue; + } + + public static int testIntSubConstant1(FieldObject f) { + return f.intValue - intTestValue1; + } + + public static int testIntSubConstant2(FieldObject f) { + return f.intValue - intTestValue2; + } + + @Test + public void testIntSubs() { + FieldObject f = new FieldObject(); + test("testIntSub", f, intTestValue1); + test("testIntSubConstant1", f); + test("testIntSubConstant2", f); + } + + @Test + public void testIntNullSub() { + test("testIntSub", null, intTestValue1); + } + + public static long testLongSub(FieldObject f, long longValue) { + return f.longValue - longValue; + } + + public static long testLongSubConstant1(FieldObject f) { + return f.longValue - longTestValue1; + } + + public static long testLongSubConstant2(FieldObject f) { + return f.longValue - longTestValue2; + } + + @Test + public void testLongSubs() { + FieldObject f = new FieldObject(); + test("testLongSub", f, longTestValue1); + test("testLongSubConstant1", f); + test("testLongSubConstant2", f); + } + + @Test + public void testLongNullSub() { + test("testLongSub", null, longTestValue1); + } + + public static float testFloatSub(FieldObject f, float floatValue) { + return f.floatValue - floatValue; + } + + public static float testFloatSubConstant1(FieldObject f) { + return f.floatValue - floatTestValue1; + } + + public static float testFloatSubConstant2(FieldObject f) { + return f.floatValue - floatTestValue2; + } + + @Test + public void testFloatSubs() { + FieldObject f = new FieldObject(); + test("testFloatSub", f, floatTestValue1); + test("testFloatSubConstant1", f); + test("testFloatSubConstant2", f); + } + + @Test + public void testFloatNullSub() { + test("testFloatSub", null, floatTestValue1); + } + + public static double testDoubleSub(FieldObject f, double doubleValue) { + return f.doubleValue - doubleValue; + } + + public static double testDoubleSubConstant1(FieldObject f) { + return f.doubleValue - doubleTestValue1; + } + + public static double testDoubleSubConstant2(FieldObject f) { + return f.doubleValue - doubleTestValue2; + } + + @Test + public void testDoubleSubs() { + FieldObject f = new FieldObject(); + test("testDoubleSub", f, doubleTestValue1); + test("testDoubleSubConstant1", f); + test("testDoubleSubConstant2", f); + } + + @Test + public void testDoubleNullSub() { + test("testDoubleSub", null, doubleTestValue1); + } + + public static int testByteMul(FieldObject f, byte byteValue) { + return f.byteValue * byteValue; + } + + public static int testByteMulConstant1(FieldObject f) { + return f.byteValue * byteTestValue1; + } + + public static int testByteMulConstant2(FieldObject f) { + return f.byteValue * byteTestValue2; + } + + @Test + public void testByteMuls() { + FieldObject f = new FieldObject(); + test("testByteMul", f, byteTestValue1); + test("testByteMulConstant1", f); + test("testByteMulConstant2", f); + } + + @Test + public void testByteNullMul() { + test("testByteMul", null, byteTestValue1); + } + + public static int testShortMul(FieldObject f, short shortValue) { + return f.shortValue * shortValue; + } + + public static int testShortMulConstant1(FieldObject f) { + return f.shortValue * shortTestValue1; + } + + public static int testShortMulConstant2(FieldObject f) { + return f.shortValue * shortTestValue2; + } + + @Test + public void testShortMuls() { + FieldObject f = new FieldObject(); + test("testShortMul", f, shortTestValue1); + test("testShortMulConstant1", f); + test("testShortMulConstant2", f); + } + + @Test + public void testShortNullMul() { + test("testShortMul", null, shortTestValue1); + } + + public static int testCharMul(FieldObject f, char charValue) { + return f.charValue * charValue; + } + + public static int testCharMulConstant1(FieldObject f) { + return f.charValue * charTestValue1; + } + + public static int testCharMulConstant2(FieldObject f) { + return f.charValue * charTestValue2; + } + + @Test + public void testCharMuls() { + FieldObject f = new FieldObject(); + test("testCharMul", f, charTestValue1); + test("testCharMulConstant1", f); + test("testCharMulConstant2", f); + } + + @Test + public void testCharNullMul() { + test("testCharMul", null, charTestValue1); + } + + public static int testIntMul(FieldObject f, int intValue) { + return f.intValue * intValue; + } + + public static int testIntMulConstant1(FieldObject f) { + return f.intValue * intTestValue1; + } + + public static int testIntMulConstant2(FieldObject f) { + return f.intValue * intTestValue2; + } + + @Test + public void testIntMuls() { + FieldObject f = new FieldObject(); + test("testIntMul", f, intTestValue1); + test("testIntMulConstant1", f); + test("testIntMulConstant2", f); + } + + @Test + public void testIntNullMul() { + test("testIntMul", null, intTestValue1); + } + + public static long testLongMul(FieldObject f, long longValue) { + return f.longValue * longValue; + } + + public static long testLongMulConstant1(FieldObject f) { + return f.longValue * longTestValue1; + } + + public static long testLongMulConstant2(FieldObject f) { + return f.longValue * longTestValue2; + } + + @Test + public void testLongMuls() { + FieldObject f = new FieldObject(); + test("testLongMul", f, longTestValue1); + test("testLongMulConstant1", f); + test("testLongMulConstant2", f); + } + + @Test + public void testLongNullMul() { + test("testLongMul", null, longTestValue1); + } + + public static float testFloatMul(FieldObject f, float floatValue) { + return f.floatValue * floatValue; + } + + public static float testFloatMulConstant1(FieldObject f) { + return f.floatValue * floatTestValue1; + } + + public static float testFloatMulConstant2(FieldObject f) { + return f.floatValue * floatTestValue2; + } + + @Test + public void testFloatMuls() { + FieldObject f = new FieldObject(); + test("testFloatMul", f, floatTestValue1); + test("testFloatMulConstant1", f); + test("testFloatMulConstant2", f); + } + + @Test + public void testFloatNullMul() { + test("testFloatMul", null, floatTestValue1); + } + + public static double testDoubleMul(FieldObject f, double doubleValue) { + return f.doubleValue * doubleValue; + } + + public static double testDoubleMulConstant1(FieldObject f) { + return f.doubleValue * doubleTestValue1; + } + + public static double testDoubleMulConstant2(FieldObject f) { + return f.doubleValue * doubleTestValue2; + } + + @Test + public void testDoubleMuls() { + FieldObject f = new FieldObject(); + test("testDoubleMul", f, doubleTestValue1); + test("testDoubleMulConstant1", f); + test("testDoubleMulConstant2", f); + } + + @Test + public void testDoubleNullMul() { + test("testDoubleMul", null, doubleTestValue1); + } + + public static int testByteDiv(FieldObject f, byte byteValue) { + return f.byteValue / byteValue; + } + + public static int testByteDivConstant1(FieldObject f) { + return f.byteValue / byteTestValue1; + } + + public static int testByteDivConstant2(FieldObject f) { + return f.byteValue / byteTestValue2; + } + + @Test + public void testByteDivs() { + FieldObject f = new FieldObject(); + test("testByteDiv", f, byteTestValue1); + test("testByteDivConstant1", f); + test("testByteDivConstant2", f); + } + + @Test + public void testByteNullDiv() { + test("testByteDiv", null, byteTestValue1); + } + + public static int testShortDiv(FieldObject f, short shortValue) { + return f.shortValue / shortValue; + } + + public static int testShortDivConstant1(FieldObject f) { + return f.shortValue / shortTestValue1; + } + + public static int testShortDivConstant2(FieldObject f) { + return f.shortValue / shortTestValue2; + } + + @Test + public void testShortDivs() { + FieldObject f = new FieldObject(); + test("testShortDiv", f, shortTestValue1); + test("testShortDivConstant1", f); + test("testShortDivConstant2", f); + } + + @Test + public void testShortNullDiv() { + test("testShortDiv", null, shortTestValue1); + } + + public static int testCharDiv(FieldObject f, char charValue) { + return f.charValue / charValue; + } + + public static int testCharDivConstant1(FieldObject f) { + return f.charValue / charTestValue1; + } + + public static int testCharDivConstant2(FieldObject f) { + return f.charValue / charTestValue2; + } + + @Test + public void testCharDivs() { + FieldObject f = new FieldObject(); + test("testCharDiv", f, charTestValue1); + test("testCharDivConstant1", f); + test("testCharDivConstant2", f); + } + + @Test + public void testCharNullDiv() { + test("testCharDiv", null, charTestValue1); + } + + public static int testIntDiv(FieldObject f, int intValue) { + return f.intValue / intValue; + } + + public static int testIntDivConstant1(FieldObject f) { + return f.intValue / intTestValue1; + } + + public static int testIntDivConstant2(FieldObject f) { + return f.intValue / intTestValue2; + } + + @Test + public void testIntDivs() { + FieldObject f = new FieldObject(); + test("testIntDiv", f, intTestValue1); + test("testIntDivConstant1", f); + test("testIntDivConstant2", f); + } + + @Test + public void testIntNullDiv() { + test("testIntDiv", null, intTestValue1); + } + + public static long testLongDiv(FieldObject f, long longValue) { + return f.longValue / longValue; + } + + public static long testLongDivConstant1(FieldObject f) { + return f.longValue / longTestValue1; + } + + public static long testLongDivConstant2(FieldObject f) { + return f.longValue / longTestValue2; + } + + @Test + public void testLongDivs() { + FieldObject f = new FieldObject(); + test("testLongDiv", f, longTestValue1); + test("testLongDivConstant1", f); + test("testLongDivConstant2", f); + } + + @Test + public void testLongNullDiv() { + test("testLongDiv", null, longTestValue1); + } + + public static float testFloatDiv(FieldObject f, float floatValue) { + return f.floatValue / floatValue; + } + + public static float testFloatDivConstant1(FieldObject f) { + return f.floatValue / floatTestValue1; + } + + public static float testFloatDivConstant2(FieldObject f) { + return f.floatValue / floatTestValue2; + } + + @Test + public void testFloatDivs() { + FieldObject f = new FieldObject(); + test("testFloatDiv", f, floatTestValue1); + test("testFloatDivConstant1", f); + test("testFloatDivConstant2", f); + } + + @Test + public void testFloatNullDiv() { + test("testFloatDiv", null, floatTestValue1); + } + + public static double testDoubleDiv(FieldObject f, double doubleValue) { + return f.doubleValue / doubleValue; + } + + public static double testDoubleDivConstant1(FieldObject f) { + return f.doubleValue / doubleTestValue1; + } + + public static double testDoubleDivConstant2(FieldObject f) { + return f.doubleValue / doubleTestValue2; + } + + @Test + public void testDoubleDivs() { + FieldObject f = new FieldObject(); + test("testDoubleDiv", f, doubleTestValue1); + test("testDoubleDivConstant1", f); + test("testDoubleDivConstant2", f); + } + + @Test + public void testDoubleNullDiv() { + test("testDoubleDiv", null, doubleTestValue1); + } + + public static int testByteOr(FieldObject f, byte byteValue) { + return f.byteValue | byteValue; + } + + public static int testByteOrConstant1(FieldObject f) { + return f.byteValue | byteTestValue1; + } + + public static int testByteOrConstant2(FieldObject f) { + return f.byteValue | byteTestValue2; + } + + @Test + public void testByteOrs() { + FieldObject f = new FieldObject(); + test("testByteOr", f, byteTestValue1); + test("testByteOrConstant1", f); + test("testByteOrConstant2", f); + } + + @Test + public void testByteNullOr() { + test("testByteOr", null, byteTestValue1); + } + + public static int testShortOr(FieldObject f, short shortValue) { + return f.shortValue | shortValue; + } + + public static int testShortOrConstant1(FieldObject f) { + return f.shortValue | shortTestValue1; + } + + public static int testShortOrConstant2(FieldObject f) { + return f.shortValue | shortTestValue2; + } + + @Test + public void testShortOrs() { + FieldObject f = new FieldObject(); + test("testShortOr", f, shortTestValue1); + test("testShortOrConstant1", f); + test("testShortOrConstant2", f); + } + + @Test + public void testShortNullOr() { + test("testShortOr", null, shortTestValue1); + } + + public static int testCharOr(FieldObject f, char charValue) { + return f.charValue | charValue; + } + + public static int testCharOrConstant1(FieldObject f) { + return f.charValue | charTestValue1; + } + + public static int testCharOrConstant2(FieldObject f) { + return f.charValue | charTestValue2; + } + + @Test + public void testCharOrs() { + FieldObject f = new FieldObject(); + test("testCharOr", f, charTestValue1); + test("testCharOrConstant1", f); + test("testCharOrConstant2", f); + } + + @Test + public void testCharNullOr() { + test("testCharOr", null, charTestValue1); + } + + public static int testIntOr(FieldObject f, int intValue) { + return f.intValue | intValue; + } + + public static int testIntOrConstant1(FieldObject f) { + return f.intValue | intTestValue1; + } + + public static int testIntOrConstant2(FieldObject f) { + return f.intValue | intTestValue2; + } + + @Test + public void testIntOrs() { + FieldObject f = new FieldObject(); + test("testIntOr", f, intTestValue1); + test("testIntOrConstant1", f); + test("testIntOrConstant2", f); + } + + @Test + public void testIntNullOr() { + test("testIntOr", null, intTestValue1); + } + + public static long testLongOr(FieldObject f, long longValue) { + return f.longValue | longValue; + } + + public static long testLongOrConstant1(FieldObject f) { + return f.longValue | longTestValue1; + } + + public static long testLongOrConstant2(FieldObject f) { + return f.longValue | longTestValue2; + } + + @Test + public void testLongOrs() { + FieldObject f = new FieldObject(); + test("testLongOr", f, longTestValue1); + test("testLongOrConstant1", f); + test("testLongOrConstant2", f); + } + + @Test + public void testLongNullOr() { + test("testLongOr", null, longTestValue1); + } + + public static int testByteXor(FieldObject f, byte byteValue) { + return f.byteValue ^ byteValue; + } + + public static int testByteXorConstant1(FieldObject f) { + return f.byteValue ^ byteTestValue1; + } + + public static int testByteXorConstant2(FieldObject f) { + return f.byteValue ^ byteTestValue2; + } + + @Test + public void testByteXors() { + FieldObject f = new FieldObject(); + test("testByteXor", f, byteTestValue1); + test("testByteXorConstant1", f); + test("testByteXorConstant2", f); + } + + @Test + public void testByteNullXor() { + test("testByteXor", null, byteTestValue1); + } + + public static int testShortXor(FieldObject f, short shortValue) { + return f.shortValue ^ shortValue; + } + + public static int testShortXorConstant1(FieldObject f) { + return f.shortValue ^ shortTestValue1; + } + + public static int testShortXorConstant2(FieldObject f) { + return f.shortValue ^ shortTestValue2; + } + + @Test + public void testShortXors() { + FieldObject f = new FieldObject(); + test("testShortXor", f, shortTestValue1); + test("testShortXorConstant1", f); + test("testShortXorConstant2", f); + } + + @Test + public void testShortNullXor() { + test("testShortXor", null, shortTestValue1); + } + + public static int testCharXor(FieldObject f, char charValue) { + return f.charValue ^ charValue; + } + + public static int testCharXorConstant1(FieldObject f) { + return f.charValue ^ charTestValue1; + } + + public static int testCharXorConstant2(FieldObject f) { + return f.charValue ^ charTestValue2; + } + + @Test + public void testCharXors() { + FieldObject f = new FieldObject(); + test("testCharXor", f, charTestValue1); + test("testCharXorConstant1", f); + test("testCharXorConstant2", f); + } + + @Test + public void testCharNullXor() { + test("testCharXor", null, charTestValue1); + } + + public static int testIntXor(FieldObject f, int intValue) { + return f.intValue ^ intValue; + } + + public static int testIntXorConstant1(FieldObject f) { + return f.intValue ^ intTestValue1; + } + + public static int testIntXorConstant2(FieldObject f) { + return f.intValue ^ intTestValue2; + } + + @Test + public void testIntXors() { + FieldObject f = new FieldObject(); + test("testIntXor", f, intTestValue1); + test("testIntXorConstant1", f); + test("testIntXorConstant2", f); + } + + @Test + public void testIntNullXor() { + test("testIntXor", null, intTestValue1); + } + + public static long testLongXor(FieldObject f, long longValue) { + return f.longValue ^ longValue; + } + + public static long testLongXorConstant1(FieldObject f) { + return f.longValue ^ longTestValue1; + } + + public static long testLongXorConstant2(FieldObject f) { + return f.longValue ^ longTestValue2; + } + + @Test + public void testLongXors() { + FieldObject f = new FieldObject(); + test("testLongXor", f, longTestValue1); + test("testLongXorConstant1", f); + test("testLongXorConstant2", f); + } + + @Test + public void testLongNullXor() { + test("testLongXor", null, longTestValue1); + } + + public static int testByteAnd(FieldObject f, byte byteValue) { + return f.byteValue & byteValue; + } + + public static int testByteAndConstant1(FieldObject f) { + return f.byteValue & byteTestValue1; + } + + public static int testByteAndConstant2(FieldObject f) { + return f.byteValue & byteTestValue2; + } + + @Test + public void testByteAnds() { + FieldObject f = new FieldObject(); + test("testByteAnd", f, byteTestValue1); + test("testByteAndConstant1", f); + test("testByteAndConstant2", f); + } + + @Test + public void testByteNullAnd() { + test("testByteAnd", null, byteTestValue1); + } + + public static int testShortAnd(FieldObject f, short shortValue) { + return f.shortValue & shortValue; + } + + public static int testShortAndConstant1(FieldObject f) { + return f.shortValue & shortTestValue1; + } + + public static int testShortAndConstant2(FieldObject f) { + return f.shortValue & shortTestValue2; + } + + @Test + public void testShortAnds() { + FieldObject f = new FieldObject(); + test("testShortAnd", f, shortTestValue1); + test("testShortAndConstant1", f); + test("testShortAndConstant2", f); + } + + @Test + public void testShortNullAnd() { + test("testShortAnd", null, shortTestValue1); + } + + public static int testCharAnd(FieldObject f, char charValue) { + return f.charValue & charValue; + } + + public static int testCharAndConstant1(FieldObject f) { + return f.charValue & charTestValue1; + } + + public static int testCharAndConstant2(FieldObject f) { + return f.charValue & charTestValue2; + } + + @Test + public void testCharAnds() { + FieldObject f = new FieldObject(); + test("testCharAnd", f, charTestValue1); + test("testCharAndConstant1", f); + test("testCharAndConstant2", f); + } + + @Test + public void testCharNullAnd() { + test("testCharAnd", null, charTestValue1); + } + + public static int testIntAnd(FieldObject f, int intValue) { + return f.intValue & intValue; + } + + public static int testIntAndConstant1(FieldObject f) { + return f.intValue & intTestValue1; + } + + public static int testIntAndConstant2(FieldObject f) { + return f.intValue & intTestValue2; + } + + @Test + public void testIntAnds() { + FieldObject f = new FieldObject(); + test("testIntAnd", f, intTestValue1); + test("testIntAndConstant1", f); + test("testIntAndConstant2", f); + } + + @Test + public void testIntNullAnd() { + test("testIntAnd", null, intTestValue1); + } + + public static long testLongAnd(FieldObject f, long longValue) { + return f.longValue & longValue; + } + + public static long testLongAndConstant1(FieldObject f) { + return f.longValue & longTestValue1; + } + + public static long testLongAndConstant2(FieldObject f) { + return f.longValue & longTestValue2; + } + + @Test + public void testLongAnds() { + FieldObject f = new FieldObject(); + test("testLongAnd", f, longTestValue1); + test("testLongAndConstant1", f); + test("testLongAndConstant2", f); + } + + @Test + public void testLongNullAnd() { + test("testLongAnd", null, longTestValue1); + } + + public static boolean testIntMask(FieldObject f, int intValue) { + if ((f.intValue & intValue) != 0) { + count++; + return false; + } + return true; + } + + public static boolean testIntMaskConstant1(FieldObject f) { + return (f.intValue & intTestValue1) != 0; + } + + public static boolean testIntMaskConstant2(FieldObject f) { + return (f.intValue & intTestValue2) != 0; + } + + @Test + public void testIntMasks() { + FieldObject f = new FieldObject(); + test("testIntMask", f, intTestValue1); + test("testIntMaskConstant1", f); + test("testIntMaskConstant2", f); + } + + @Test + public void testIntNullMask() { + test("testIntMask", null, intTestValue1); + } + + public static boolean testLongMask(FieldObject f, long longValue) { + if ((f.longValue & longValue) != 0) { + count++; + return false; + } + return true; + } + + public static boolean testLongMaskConstant1(FieldObject f) { + return (f.longValue & longTestValue1) != 0; + } + + public static boolean testLongMaskConstant2(FieldObject f) { + return (f.longValue & longTestValue2) != 0; + } + + @Test + public void testLongMasks() { + FieldObject f = new FieldObject(); + test("testLongMask", f, longTestValue1); + test("testLongMaskConstant1", f); + test("testLongMaskConstant2", f); + } + + @Test + public void testLongNullMask() { + test("testLongMask", null, longTestValue1); + } + + public static int doConvertByteInt(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteInt() { + test("doConvertByteInt", maxObject); + test("doConvertByteInt", (FieldObject) null); + } + + public static int doConvertShortInt(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortInt() { + test("doConvertShortInt", maxObject); + test("doConvertShortInt", (FieldObject) null); + } + + public static int doConvertCharInt(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharInt() { + test("doConvertCharInt", maxObject); + test("doConvertCharInt", (FieldObject) null); + } + + public static int doConvertLongInt(FieldObject f) { + return (int) f.longValue; + } + + @Test + public void testConvertLongInt() { + test("doConvertLongInt", maxObject); + test("doConvertLongInt", (FieldObject) null); + } + + public static int doConvertFloatInt(FieldObject f) { + return (int) f.floatValue; + } + + @Test + public void testConvertFloatInt() { + test("doConvertFloatInt", maxObject); + test("doConvertFloatInt", (FieldObject) null); + } + + public static int doConvertDoubleInt(FieldObject f) { + return (int) f.doubleValue; + } + + @Test + public void testConvertDoubleInt() { + test("doConvertDoubleInt", maxObject); + test("doConvertDoubleInt", (FieldObject) null); + } + + public static long doConvertByteLong(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteLong() { + test("doConvertByteLong", maxObject); + test("doConvertByteLong", (FieldObject) null); + } + + public static long doConvertShortLong(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortLong() { + test("doConvertShortLong", maxObject); + test("doConvertShortLong", (FieldObject) null); + } + + public static long doConvertCharLong(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharLong() { + test("doConvertCharLong", maxObject); + test("doConvertCharLong", (FieldObject) null); + } + + public static long doConvertIntLong(FieldObject f) { + return f.intValue; + } + + @Test + public void testConvertIntLong() { + test("doConvertIntLong", maxObject); + test("doConvertIntLong", (FieldObject) null); + } + + public static long doConvertFloatLong(FieldObject f) { + return (long) f.floatValue; + } + + @Test + public void testConvertFloatLong() { + test("doConvertFloatLong", maxObject); + test("doConvertFloatLong", (FieldObject) null); + } + + public static long doConvertDoubleLong(FieldObject f) { + return (long) f.doubleValue; + } + + @Test + public void testConvertDoubleLong() { + test("doConvertDoubleLong", maxObject); + test("doConvertDoubleLong", (FieldObject) null); + } + + public static float doConvertByteFloat(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteFloat() { + test("doConvertByteFloat", maxObject); + test("doConvertByteFloat", (FieldObject) null); + } + + public static float doConvertShortFloat(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortFloat() { + test("doConvertShortFloat", maxObject); + test("doConvertShortFloat", (FieldObject) null); + } + + public static float doConvertCharFloat(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharFloat() { + test("doConvertCharFloat", maxObject); + test("doConvertCharFloat", (FieldObject) null); + } + + public static float doConvertIntFloat(FieldObject f) { + return f.intValue; + } + + @Test + public void testConvertIntFloat() { + test("doConvertIntFloat", maxObject); + test("doConvertIntFloat", (FieldObject) null); + } + + public static float doConvertLongFloat(FieldObject f) { + return f.longValue; + } + + @Test + public void testConvertLongFloat() { + test("doConvertLongFloat", maxObject); + test("doConvertLongFloat", (FieldObject) null); + } + + public static float doConvertDoubleFloat(FieldObject f) { + return (float) f.doubleValue; + } + + @Test + public void testConvertDoubleFloat() { + test("doConvertDoubleFloat", maxObject); + test("doConvertDoubleFloat", (FieldObject) null); + } + + public static double doConvertByteDouble(FieldObject f) { + return f.byteValue; + } + + @Test + public void testConvertByteDouble() { + test("doConvertByteDouble", maxObject); + test("doConvertByteDouble", (FieldObject) null); + } + + public static double doConvertShortDouble(FieldObject f) { + return f.shortValue; + } + + @Test + public void testConvertShortDouble() { + test("doConvertShortDouble", maxObject); + test("doConvertShortDouble", (FieldObject) null); + } + + public static double doConvertCharDouble(FieldObject f) { + return f.charValue; + } + + @Test + public void testConvertCharDouble() { + test("doConvertCharDouble", maxObject); + test("doConvertCharDouble", (FieldObject) null); + } + + public static double doConvertIntDouble(FieldObject f) { + return f.intValue; + } + + @Test + public void testConvertIntDouble() { + test("doConvertIntDouble", maxObject); + test("doConvertIntDouble", (FieldObject) null); + } + + public static double doConvertLongDouble(FieldObject f) { + return f.longValue; + } + + @Test + public void testConvertLongDouble() { + test("doConvertLongDouble", maxObject); + test("doConvertLongDouble", (FieldObject) null); + } + + public static double doConvertFloatDouble(FieldObject f) { + return f.floatValue; + } + + @Test + public void testConvertFloatDouble() { + test("doConvertFloatDouble", maxObject); + test("doConvertFloatDouble", (FieldObject) null); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -73,8 +73,8 @@ public RegisterStats(LIR lir) { this.lir = lir; - for (Block block : lir.codeEmittingOrder()) { - for (LIRInstruction instr : lir.lir(block)) { + for (AbstractBlock block : lir.codeEmittingOrder()) { + for (LIRInstruction instr : lir.getLIRforBlock(block)) { collectStats(instr); } } @@ -120,7 +120,7 @@ } CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); - LIRGenerator lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc); - return new RegisterStats(lirGen.lir); + LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc); + return new RegisterStats(lirGen.getLIR()); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -59,7 +59,7 @@ new DeadCodeEliminationPhase().apply(graph); for (ConstantNode node : ConstantNode.getConstantNodes(graph)) { - if (node.kind() == Kind.Object && " ".equals(node.getValue().asObject())) { + if (node.getKind() == Kind.Object && " ".equals(node.getValue().asObject())) { node.replace(graph, ConstantNode.forObject("-", getMetaAccess(), graph)); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + */ +package com.oracle.graal.compiler.test.deopt; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; + +public final class MonitorDeoptTest extends GraalCompilerTest { + + private enum State { + INITIAL, RUNNING_GRAAL, INVALIDATED, RUNNING_INTERPRETER, TERMINATED + } + + private static class Monitor { + private volatile State state = State.INITIAL; + + public synchronized void setState(State newState) { + state = newState; + notifyAll(); + } + + public synchronized boolean tryUpdateState(State oldState, State newState) { + if (state == oldState) { + state = newState; + notifyAll(); + return true; + } else { + return false; + } + } + + public synchronized void waitState(State targetState) throws InterruptedException { + while (state != targetState) { + wait(); + } + } + + public synchronized State getState() { + return state; + } + + public synchronized void invalidate(InstalledCode code) { + state = State.INVALIDATED; + code.invalidate(); + } + } + + public static boolean test(Monitor monitor) { + // initially, we're running as Graal compiled code + monitor.setState(State.RUNNING_GRAAL); + + for (;;) { + // wait for the compiled code to be invalidated + if (monitor.tryUpdateState(State.INVALIDATED, State.RUNNING_INTERPRETER)) { + break; + } + } + + for (int i = 0; i < 500; i++) { + // wait for the control thread to send the TERMINATED signal + if (monitor.getState() == State.TERMINATED) { + return true; + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + + // we're running for more than 5 s in the interpreter + // probably the control thread is deadlocked + return false; + } + + private static LoopBeginNode findFirstLoop(StructuredGraph graph) { + FixedNode node = graph.start(); + for (;;) { + if (node instanceof LoopBeginNode) { + return (LoopBeginNode) node; + } else if (node instanceof FixedWithNextNode) { + node = ((FixedWithNextNode) node).next(); + } else if (node instanceof AbstractEndNode) { + node = ((AbstractEndNode) node).merge(); + } else { + Assert.fail(String.format("unexpected node %s in graph of test method", node)); + } + } + } + + /** + * Remove the safepoint from the first loop in the test method, so only the safepoints on + * MonitorEnter and MonitorExit remain in the loop. That way, we can make sure it deopts inside + * the MonitorEnter by invalidating the code while holding the lock. + */ + private static void removeLoopSafepoint(StructuredGraph graph) { + LoopBeginNode loopBegin = findFirstLoop(graph); + for (LoopEndNode end : loopBegin.loopEnds()) { + end.disableSafepoint(); + } + } + + @Test + public void run0() throws Throwable { + Method method = getMethod("test"); + + StructuredGraph graph = parse(method); + removeLoopSafepoint(graph); + + ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method); + CompilationResult compilationResult = compile(javaMethod, graph); + final InstalledCode installedCode = getProviders().getCodeCache().setDefaultMethod(javaMethod, compilationResult); + + final Monitor monitor = new Monitor(); + + Thread controlThread = new Thread(new Runnable() { + + public void run() { + try { + // wait for the main thread to start + monitor.waitState(State.RUNNING_GRAAL); + + // invalidate the compiled code while holding the lock + // at this point, the compiled method hangs in a MonitorEnter + monitor.invalidate(installedCode); + + // wait for the main thread to continue running in the interpreter + monitor.waitState(State.RUNNING_INTERPRETER); + + // terminate the main thread + monitor.setState(State.TERMINATED); + } catch (InterruptedException e) { + } + } + }); + + controlThread.start(); + + boolean result = test(monitor); + Assert.assertTrue(result); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Sun Mar 30 16:08:33 2014 +0200 @@ -149,7 +149,7 @@ protected void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) { ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet)); graph = new StructuredGraph(method); - try (Scope s = Debug.scope(getClass().getSimpleName(), graph, method, getCodeCache())) { + try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) { new GraphBuilderPhase.Instance(getMetaAccess(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); Assumptions assumptions = new Assumptions(false); context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,83 @@ +/* + * 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.compiler.test.ea; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; + +/** + * Tests {@link AbstractNewObjectNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)}. + * + */ +public class PoorMansEATest extends GraalCompilerTest { + public static class A { + public A obj; + } + + public static A test1Snippet() { + A a = new A(); + a.obj = a; + return null; + } + + @Test + public void test1() { + test("test1Snippet"); + } + + private void test(final String snippet) { + try (Scope s = Debug.scope("PoorMansEATest", new DebugDumpScope(snippet))) { + StructuredGraph graph = parse(snippet); + Assumptions assumptions = new Assumptions(false); + HighTierContext highTierContext = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext); + PhaseContext context = new PhaseContext(getProviders(), assumptions); + new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + + // remove framestates in order to trigger the simplification. + cleanup: for (FrameState fs : graph.getNodes(FrameState.class).snapshot()) { + for (Node input : fs.inputs()) { + if (input instanceof NewInstanceNode) { + fs.replaceAtUsages(null); + fs.safeDelete(); + continue cleanup; + } + } + } + new CanonicalizerPhase(true).apply(graph, context); + } catch (Throwable e) { + throw Debug.handle(e); + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThread.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 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.compiler; + +import com.oracle.graal.compiler.CompilerThreadFactory.*; +import com.oracle.graal.debug.*; + +/** + * A compiler thread is a daemon thread that runs at {@link Thread#MAX_PRIORITY} and executes in the + * context of a thread-local {@linkplain GraalDebugConfig debug configuration}. + */ +public class CompilerThread extends Thread { + + private final DebugConfigAccess debugConfigAccess; + + public CompilerThread(Runnable r, String namePrefix, DebugConfigAccess debugConfigAccess) { + super(r); + this.setName(namePrefix + "-" + this.getId()); + this.setPriority(Thread.MAX_PRIORITY); + this.setDaemon(true); + this.debugConfigAccess = debugConfigAccess; + } + + @Override + public void run() { + GraalDebugConfig debugConfig = debugConfigAccess.getDebugConfig(); + try { + super.run(); + } finally { + if (debugConfig != null) { + for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) { + try { + dumpHandler.close(); + } catch (Throwable t) { + } + } + } + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThreadFactory.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThreadFactory.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThreadFactory.java Sun Mar 30 16:08:33 2014 +0200 @@ -53,38 +53,4 @@ public Thread newThread(Runnable r) { return new CompilerThread(r, threadNamePrefix, debugConfigAccess); } - - /** - * A compiler thread is a daemon thread that runs at {@link Thread#MAX_PRIORITY} and executes in - * the context of a thread-local {@linkplain GraalDebugConfig debug configuration}. - */ - public static class CompilerThread extends Thread { - - private final DebugConfigAccess debugConfigAccess; - - public CompilerThread(Runnable r, String namePrefix, DebugConfigAccess debugConfigAccess) { - super(r); - this.setName(namePrefix + "-" + this.getId()); - this.setPriority(Thread.MAX_PRIORITY); - this.setDaemon(true); - this.debugConfigAccess = debugConfigAccess; - } - - @Override - public void run() { - GraalDebugConfig debugConfig = debugConfigAccess.getDebugConfig(); - try { - super.run(); - } finally { - if (debugConfig != null) { - for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) { - try { - dumpHandler.close(); - } catch (Throwable t) { - } - } - } - } - } - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Sun Mar 30 16:08:33 2014 +0200 @@ -145,10 +145,10 @@ throw Debug.handle(e); } try (TimerCloseable a = BackEnd.start()) { - LIRGenerator lirGen = null; - lirGen = emitLIR(backend, target, schedule, graph, stub, cc); - try (Scope s = Debug.scope("CodeGen", lirGen)) { - emitCode(backend, assumptions, lirGen, compilationResult, installedCodeOwner, factory); + LIRGenerationResult lirGenRes = null; + lirGenRes = emitLIR(backend, target, schedule, graph, stub, cc); + try (Scope s = Debug.scope("CodeGen", lirGenRes)) { + emitCode(backend, assumptions, lirGenRes, compilationResult, installedCodeOwner, factory); } catch (Throwable e) { throw Debug.handle(e); } @@ -205,30 +205,32 @@ } - private static void emitBlock(LIRGenerator lirGen, Block b, StructuredGraph graph, BlockMap> blockMap) { - if (lirGen.lir.lir(b) == null) { + private static void emitBlock(NodeLIRGenerator nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap> blockMap) { + if (lirGenRes.getLIR().getLIRforBlock(b) == null) { for (Block pred : b.getPredecessors()) { if (!b.isLoopHeader() || !pred.isLoopEnd()) { - emitBlock(lirGen, pred, graph, blockMap); + emitBlock(nodeLirGen, lirGenRes, pred, graph, blockMap); } } - lirGen.doBlock(b, graph, blockMap); + nodeLirGen.doBlock(b, graph, blockMap); } } - public static LIRGenerator emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc) { + public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc) { Block[] blocks = schedule.getCFG().getBlocks(); Block startBlock = schedule.getCFG().getStartBlock(); assert startBlock != null; assert startBlock.getPredecessorCount() == 0; LIR lir = null; + List codeEmittingOrder = null; + List linearScanOrder = null; try (Scope ds = Debug.scope("MidEnd")) { try (Scope s = Debug.scope("ComputeLinearScanOrder")) { NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); - System.out.printf("%d, %d\n", nodeProbabilities.getCount(), graph.getNodeCount()); - List codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, nodeProbabilities); - List linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, nodeProbabilities); + BlocksToDoubles blockProbabilities = BlocksToDoubles.createFromNodeProbability(nodeProbabilities, schedule.getCFG()); + codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, blockProbabilities); + linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, blockProbabilities); lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder); Debug.dump(lir, "After linear scan order"); @@ -240,11 +242,13 @@ } try (Scope ds = Debug.scope("BackEnd", lir)) { FrameMap frameMap = backend.newFrameMap(); - LIRGenerator lirGen = backend.newLIRGenerator(graph, stub, frameMap, cc, lir); + LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMap, stub); + LIRGenerator lirGen = backend.newLIRGenerator(cc, lirGenRes); + NodeLIRGenerator nodeLirGen = backend.newNodeLIRGenerator(graph, lirGenRes, lirGen); try (Scope s = Debug.scope("LIRGen", lirGen)) { - for (Block b : lir.linearScanOrder()) { - emitBlock(lirGen, b, graph, schedule.getBlockToNodesMap()); + for (Block b : linearScanOrder) { + emitBlock(nodeLirGen, lirGenRes, b, graph, schedule.getBlockToNodesMap()); } lirGen.beforeRegisterAllocation(); @@ -253,7 +257,7 @@ throw Debug.handle(e); } - try (Scope s = Debug.scope("Allocator", lirGen)) { + try (Scope s = Debug.scope("Allocator", nodeLirGen)) { if (backend.shouldAllocateRegisters()) { new LinearScan(target, lir, frameMap).allocate(); } @@ -263,7 +267,7 @@ try (Scope s = Debug.scope("ControlFlowOptimizations")) { EdgeMoveOptimizer.optimize(lir); - ControlFlowOptimizer.optimize(lir); + ControlFlowOptimizer.optimize(lir, codeEmittingOrder); if (lirGen.canEliminateRedundantMoves()) { RedundantMoveElimination.optimize(lir, frameMap); } @@ -273,16 +277,16 @@ } catch (Throwable e) { throw Debug.handle(e); } - return lirGen; + return lirGenRes; } catch (Throwable e) { throw Debug.handle(e); } } - public static void emitCode(Backend backend, Assumptions assumptions, LIRGenerator lirGen, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, + public static void emitCode(Backend backend, Assumptions assumptions, LIRGenerationResult lirGenRes, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) { - CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGen, compilationResult, factory); - backend.emitCode(crb, lirGen.lir, installedCodeOwner); + CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, compilationResult, factory); + backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner); crb.finish(); if (!assumptions.isEmpty()) { compilationResult.setAssumptions(assumptions); @@ -290,9 +294,10 @@ if (Debug.isMeterEnabled()) { List ldp = compilationResult.getDataReferences(); - DebugMetric[] dms = new DebugMetric[Kind.values().length]; + Kind[] kindValues = Kind.values(); + DebugMetric[] dms = new DebugMetric[kindValues.length]; for (int i = 0; i < dms.length; i++) { - dms[i] = Debug.metric("DataPatches-" + Kind.values()[i].toString()); + dms[i] = Debug.metric("DataPatches-%s", kindValues[i]); } for (DataPatch dp : ldp) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Sun Mar 30 16:08:33 2014 +0200 @@ -1179,7 +1179,9 @@ String to = "?"; if (first != null && first != Range.EndMarker) { from = String.valueOf(from()); - to = String.valueOf(to()); + // to() may cache a computed value, modifying the current object, which is a bad idea + // for a printing function. Compute it directly instead. + to = String.valueOf(calcTo()); } String locationString = this.location == null ? "" : "@" + this.location; return operandNumber + ":" + operand + (isRegister(operand) ? "" : locationString) + "[" + from + "," + to + "]"; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Sun Mar 30 16:08:33 2014 +0200 @@ -135,9 +135,9 @@ LIRInstruction[] opIdToInstructionMap; /** - * Map from an instruction {@linkplain LIRInstruction#id id} to the {@linkplain Block block} - * containing the instruction. Entries should be retrieved with {@link #blockForId(int)} as the - * id is not simply an index into this array. + * Map from an instruction {@linkplain LIRInstruction#id id} to the {@linkplain AbstractBlock + * block} containing the instruction. Entries should be retrieved with {@link #blockForId(int)} + * as the id is not simply an index into this array. */ AbstractBlock[] opIdToBlockMap; @@ -172,13 +172,13 @@ } public int getFirstLirInstructionId(AbstractBlock block) { - int result = ir.lir(block).get(0).id(); + int result = ir.getLIRforBlock(block).get(0).id(); assert result >= 0; return result; } public int getLastLirInstructionId(AbstractBlock block) { - List instructions = ir.lir(block); + List instructions = ir.getLIRforBlock(block); int result = instructions.get(instructions.size() - 1).id(); assert result >= 0; return result; @@ -279,7 +279,7 @@ /** * Creates a new interval. - * + * * @param operand the operand for the interval * @return the created interval */ @@ -295,7 +295,7 @@ /** * Creates an interval as a result of splitting or spilling another interval. - * + * * @param source an interval being split of spilled * @return a new interval derived from {@code source} */ @@ -376,7 +376,7 @@ /** * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}. - * + * * @param opId an instruction {@linkplain LIRInstruction#id id} * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id} */ @@ -389,7 +389,7 @@ /** * Gets the block containing a given instruction. - * + * * @param opId an instruction {@linkplain LIRInstruction#id id} * @return the block containing the instruction denoted by {@code opId} */ @@ -408,7 +408,7 @@ /** * Determines if an {@link LIRInstruction} destroys all caller saved registers. - * + * * @param opId an instruction {@linkplain LIRInstruction#id id} * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved * registers. @@ -505,79 +505,82 @@ // called once before assignment of register numbers void eliminateSpillMoves() { - Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves"); + try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) { + + // collect all intervals that must be stored after their definition. + // the list is sorted by Interval.spillDefinitionPos + Interval interval; + interval = createUnhandledLists(mustStoreAtDefinition, null).first; + if (DetailedAsserts.getValue()) { + checkIntervals(interval); + } + + LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); + for (AbstractBlock block : sortedBlocks) { + List instructions = ir.getLIRforBlock(block); + int numInst = instructions.size(); - // collect all intervals that must be stored after their definition. - // the list is sorted by Interval.spillDefinitionPos - Interval interval; - interval = createUnhandledLists(mustStoreAtDefinition, null).first; - if (DetailedAsserts.getValue()) { - checkIntervals(interval); - } + // iterate all instructions of the block. skip the first + // because it is always a label + for (int j = 1; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + int opId = op.id(); - LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); - for (AbstractBlock block : sortedBlocks) { - List instructions = ir.lir(block); - int numInst = instructions.size(); + if (opId == -1) { + MoveOp move = (MoveOp) op; + // remove move from register to stack if the stack slot is guaranteed to be + // correct. + // only moves that have been inserted by LinearScan can be removed. + assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables"; + + Interval curInterval = intervalFor(move.getResult()); - // iterate all instructions of the block. skip the first because it is always a label - for (int j = 1; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - int opId = op.id(); + if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) { + // move target is a stack slot that is always correct, so eliminate + // instruction + if (Debug.isLogEnabled()) { + Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult())); + } + // null-instructions are deleted by assignRegNum + instructions.set(j, null); + } + + } else { + // insert move from register to stack just after + // the beginning of the interval + assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; + assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; - if (opId == -1) { - MoveOp move = (MoveOp) op; - // remove move from register to stack if the stack slot is guaranteed to be - // correct. - // only moves that have been inserted by LinearScan can be removed. - assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables"; + while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { + if (!interval.canMaterialize()) { + if (!insertionBuffer.initialized()) { + // prepare insertion buffer (appended when all instructions in + // the block are processed) + insertionBuffer.init(instructions); + } - Interval curInterval = intervalFor(move.getResult()); + AllocatableValue fromLocation = interval.location(); + AllocatableValue toLocation = canonicalSpillOpr(interval); + + assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); + assert isStackSlot(toLocation) : "to operand must be a stack slot"; - if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) { - // move target is a stack slot that is always correct, so eliminate - // instruction - if (Debug.isLogEnabled()) { - Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult())); + insertionBuffer.append(j + 1, ir.getSpillMoveFactory().createMove(toLocation, fromLocation)); + + Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId); + } + interval = interval.next; } - instructions.set(j, null); // null-instructions are deleted by assignRegNum } - - } else { - // insert move from register to stack just after the beginning of the interval - assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; - assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; - - while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { - if (!interval.canMaterialize()) { - if (!insertionBuffer.initialized()) { - // prepare insertion buffer (appended when all instructions of the - // block are processed) - insertionBuffer.init(instructions); - } - - AllocatableValue fromLocation = interval.location(); - AllocatableValue toLocation = canonicalSpillOpr(interval); + } // end of instruction iteration - assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); - assert isStackSlot(toLocation) : "to operand must be a stack slot"; - - insertionBuffer.append(j + 1, ir.getSpillMoveFactory().createMove(toLocation, fromLocation)); - - Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId); - } - interval = interval.next; - } + if (insertionBuffer.initialized()) { + insertionBuffer.finish(); } - } // end of instruction iteration + } // end of block iteration - if (insertionBuffer.initialized()) { - insertionBuffer.finish(); - } - } // end of block iteration - - assert interval == Interval.EndMarker : "missed an interval"; - indent.outdent(); + assert interval == Interval.EndMarker : "missed an interval"; + } } private static void checkIntervals(Interval interval) { @@ -624,19 +627,19 @@ // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. int numInstructions = 0; for (AbstractBlock block : sortedBlocks) { - numInstructions += ir.lir(block).size(); + numInstructions += ir.getLIRforBlock(block).size(); } // initialize with correct length opIdToInstructionMap = new LIRInstruction[numInstructions]; - opIdToBlockMap = new Block[numInstructions]; + opIdToBlockMap = new AbstractBlock[numInstructions]; int opId = 0; int index = 0; for (AbstractBlock block : sortedBlocks) { blockData.put(block, new BlockData()); - List instructions = ir.lir(block); + List instructions = ir.getLIRforBlock(block); int numInst = instructions.size(); for (int j = 0; j < numInst; j++) { @@ -676,95 +679,95 @@ // iterate all blocks for (final AbstractBlock block : sortedBlocks) { - Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId()); + try (Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId())) { + + final BitSet liveGen = new BitSet(liveSize); + final BitSet liveKill = new BitSet(liveSize); - final BitSet liveGen = new BitSet(liveSize); - final BitSet liveKill = new BitSet(liveSize); + List instructions = ir.getLIRforBlock(block); + int numInst = instructions.size(); - List instructions = ir.lir(block); - int numInst = instructions.size(); + // iterate all instructions of the block + for (int j = 0; j < numInst; j++) { + final LIRInstruction op = instructions.get(j); + + ValueProcedure useProc = new ValueProcedure() { - // iterate all instructions of the block - for (int j = 0; j < numInst; j++) { - final LIRInstruction op = instructions.get(j); + @Override + protected Value doValue(Value operand) { + if (isVariable(operand)) { + int operandNum = operandNumber(operand); + if (!liveKill.get(operandNum)) { + liveGen.set(operandNum); + Debug.log("liveGen for operand %d", operandNum); + } + if (block.getLoop() != null) { + intervalInLoop.setBit(operandNum, block.getLoop().index); + } + } - ValueProcedure useProc = new ValueProcedure() { + if (DetailedAsserts.getValue()) { + verifyInput(block, liveKill, operand); + } + return operand; + } + }; + ValueProcedure stateProc = new ValueProcedure() { - @Override - protected Value doValue(Value operand) { - if (isVariable(operand)) { + @Override + public Value doValue(Value operand) { int operandNum = operandNumber(operand); if (!liveKill.get(operandNum)) { liveGen.set(operandNum); - Debug.log("liveGen for operand %d", operandNum); - } - if (block.getLoop() != null) { - intervalInLoop.setBit(operandNum, block.getLoop().index); + Debug.log("liveGen in state for operand %d", operandNum); } - } - - if (DetailedAsserts.getValue()) { - verifyInput(block, liveKill, operand); + return operand; } - return operand; - } - }; - ValueProcedure stateProc = new ValueProcedure() { + }; + ValueProcedure defProc = new ValueProcedure() { - @Override - public Value doValue(Value operand) { - int operandNum = operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); - Debug.log("liveGen in state for operand %d", operandNum); - } - return operand; - } - }; - ValueProcedure defProc = new ValueProcedure() { + @Override + public Value doValue(Value operand) { + if (isVariable(operand)) { + int varNum = operandNumber(operand); + liveKill.set(varNum); + Debug.log("liveKill for operand %d", varNum); + if (block.getLoop() != null) { + intervalInLoop.setBit(varNum, block.getLoop().index); + } + } - @Override - public Value doValue(Value operand) { - if (isVariable(operand)) { - int varNum = operandNumber(operand); - liveKill.set(varNum); - Debug.log("liveKill for operand %d", varNum); - if (block.getLoop() != null) { - intervalInLoop.setBit(varNum, block.getLoop().index); + if (DetailedAsserts.getValue()) { + // fixed intervals are never live at block boundaries, so + // they need not be processed in live sets + // process them only in debug mode so that this can be checked + verifyTemp(liveKill, operand); } + return operand; } - - if (DetailedAsserts.getValue()) { - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets - // process them only in debug mode so that this can be checked - verifyTemp(liveKill, operand); - } - return operand; - } - }; + }; - try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) { - op.forEachInput(useProc); - op.forEachAlive(useProc); - // Add uses of live locals from interpreter's point of view for proper debug - // information generation - op.forEachState(stateProc); - op.forEachTemp(defProc); - op.forEachOutput(defProc); - } - } // end of instruction iteration + try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) { + op.forEachInput(useProc); + op.forEachAlive(useProc); + // Add uses of live locals from interpreter's point of view for proper debug + // information generation + op.forEachState(stateProc); + op.forEachTemp(defProc); + op.forEachOutput(defProc); + } + } // end of instruction iteration - BlockData blockSets = blockData.get(block); - blockSets.liveGen = liveGen; - blockSets.liveKill = liveKill; - blockSets.liveIn = new BitSet(liveSize); - blockSets.liveOut = new BitSet(liveSize); + BlockData blockSets = blockData.get(block); + blockSets.liveGen = liveGen; + blockSets.liveKill = liveKill; + blockSets.liveIn = new BitSet(liveSize); + blockSets.liveOut = new BitSet(liveSize); - Debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); - Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill); + Debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); + Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill); - indent.outdent(); + } } // end of block iteration } @@ -797,92 +800,93 @@ * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block. */ void computeGlobalLiveSets() { - Indent indent = Debug.logAndIndent("compute global live sets"); - int numBlocks = blockCount(); - boolean changeOccurred; - boolean changeOccurredInBlock; - int iterationCount = 0; - BitSet liveOut = new BitSet(liveSetSize()); // scratch set for calculations + try (Indent indent = Debug.logAndIndent("compute global live sets")) { + int numBlocks = blockCount(); + boolean changeOccurred; + boolean changeOccurredInBlock; + int iterationCount = 0; + BitSet liveOut = new BitSet(liveSetSize()); // scratch set for calculations - // Perform a backward dataflow analysis to compute liveOut and liveIn for each block. - // The loop is executed until a fixpoint is reached (no changes in an iteration) - do { - changeOccurred = false; + // Perform a backward dataflow analysis to compute liveOut and liveIn for each block. + // The loop is executed until a fixpoint is reached (no changes in an iteration) + do { + changeOccurred = false; - Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount); + try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) { - // iterate all blocks in reverse order - for (int i = numBlocks - 1; i >= 0; i--) { - AbstractBlock block = blockAt(i); - BlockData blockSets = blockData.get(block); + // iterate all blocks in reverse order + for (int i = numBlocks - 1; i >= 0; i--) { + AbstractBlock block = blockAt(i); + BlockData blockSets = blockData.get(block); - changeOccurredInBlock = false; + changeOccurredInBlock = false; - // liveOut(block) is the union of liveIn(sux), for successors sux of block - int n = block.getSuccessorCount(); - if (n > 0) { - // block has successors - if (n > 0) { - liveOut.clear(); - for (AbstractBlock successor : block.getSuccessors()) { - liveOut.or(blockData.get(successor).liveIn); + // liveOut(block) is the union of liveIn(sux), for successors sux of block + int n = block.getSuccessorCount(); + if (n > 0) { + // block has successors + if (n > 0) { + liveOut.clear(); + for (AbstractBlock successor : block.getSuccessors()) { + liveOut.or(blockData.get(successor).liveIn); + } + } else { + liveOut.clear(); + } + + if (!blockSets.liveOut.equals(liveOut)) { + // A change occurred. Swap the old and new live out + // sets to avoid copying. + BitSet temp = blockSets.liveOut; + blockSets.liveOut = liveOut; + liveOut = temp; + + changeOccurred = true; + changeOccurredInBlock = true; + } } - } else { - liveOut.clear(); - } - if (!blockSets.liveOut.equals(liveOut)) { - // A change occurred. Swap the old and new live out sets to avoid copying. - BitSet temp = blockSets.liveOut; - blockSets.liveOut = liveOut; - liveOut = temp; + if (iterationCount == 0 || changeOccurredInBlock) { + // liveIn(block) is the union of liveGen(block) with (liveOut(block) & + // !liveKill(block)) + // note: liveIn has to be computed only in first iteration + // or if liveOut has changed! + BitSet liveIn = blockSets.liveIn; + liveIn.clear(); + liveIn.or(blockSets.liveOut); + liveIn.andNot(blockSets.liveKill); + liveIn.or(blockSets.liveGen); - changeOccurred = true; - changeOccurredInBlock = true; + Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); + } + } + iterationCount++; + + if (changeOccurred && iterationCount > 50) { + throw new BailoutException("too many iterations in computeGlobalLiveSets"); } } + } while (changeOccurred); - if (iterationCount == 0 || changeOccurredInBlock) { - // liveIn(block) is the union of liveGen(block) with (liveOut(block) & - // !liveKill(block)) - // note: liveIn has to be computed only in first iteration or if liveOut has - // changed! - BitSet liveIn = blockSets.liveIn; - liveIn.clear(); - liveIn.or(blockSets.liveOut); - liveIn.andNot(blockSets.liveKill); - liveIn.or(blockSets.liveGen); - - Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); - } + if (DetailedAsserts.getValue()) { + verifyLiveness(); } - iterationCount++; - if (changeOccurred && iterationCount > 50) { - throw new BailoutException("too many iterations in computeGlobalLiveSets"); + // check that the liveIn set of the first block is empty + AbstractBlock startBlock = ir.getControlFlowGraph().getStartBlock(); + if (blockData.get(startBlock).liveIn.cardinality() != 0) { + if (DetailedAsserts.getValue()) { + reportFailure(numBlocks); + } + // bailout if this occurs in product mode. + throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn); } - indent2.outdent(); - } while (changeOccurred); - - if (DetailedAsserts.getValue()) { - verifyLiveness(); } - - // check that the liveIn set of the first block is empty - Block startBlock = ir.getControlFlowGraph().getStartBlock(); - if (blockData.get(startBlock).liveIn.cardinality() != 0) { - if (DetailedAsserts.getValue()) { - reportFailure(numBlocks); - } - // bailout if this occurs in product mode. - throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn); - } - indent.outdent(); } - private static LIRGenerator getLIRGeneratorFromDebugContext() { + private static NodeLIRGenerator getNodeLIRGeneratorFromDebugContext() { if (Debug.isEnabled()) { - LIRGenerator lirGen = Debug.contextLookup(LIRGenerator.class); + NodeLIRGenerator lirGen = Debug.contextLookup(NodeLIRGenerator.class); assert lirGen != null; return lirGen; } @@ -890,7 +894,7 @@ } private static ValueNode getValueForOperandFromDebugContext(Value value) { - LIRGenerator gen = getLIRGeneratorFromDebugContext(); + NodeLIRGenerator gen = getNodeLIRGeneratorFromDebugContext(); if (gen != null) { return gen.valueForOperand(value); } @@ -899,76 +903,76 @@ private void reportFailure(int numBlocks) { try (Scope s = Debug.forceLog()) { - Indent indent = Debug.logAndIndent("report failure"); + try (Indent indent = Debug.logAndIndent("report failure")) { - BitSet startBlockLiveIn = blockData.get(ir.getControlFlowGraph().getStartBlock()).liveIn; - try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { + BitSet startBlockLiveIn = blockData.get(ir.getControlFlowGraph().getStartBlock()).liveIn; + try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { + for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { + Value operand = operandFor(operandNum); + Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand)); + } + } + + // print some additional information to simplify debugging for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { Value operand = operandFor(operandNum); - Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand)); - } - } + try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand))) { - // print some additional information to simplify debugging - for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { - Value operand = operandFor(operandNum); - final Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand)); + Deque> definedIn = new ArrayDeque<>(); + HashSet> usedIn = new HashSet<>(); + for (AbstractBlock block : sortedBlocks) { + if (blockData.get(block).liveGen.get(operandNum)) { + usedIn.add(block); + try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { + for (LIRInstruction ins : ir.getLIRforBlock(block)) { + try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { + ins.forEachState(new ValueProcedure() { - Deque> definedIn = new ArrayDeque<>(); - HashSet> usedIn = new HashSet<>(); - for (AbstractBlock block : sortedBlocks) { - if (blockData.get(block).liveGen.get(operandNum)) { - usedIn.add(block); - try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { - for (LIRInstruction ins : ir.lir(block)) { - try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { - ins.forEachState(new ValueProcedure() { - - @Override - public Value doValue(Value liveStateOperand) { - Debug.log("operand=%s", liveStateOperand); - return liveStateOperand; + @Override + public Value doValue(Value liveStateOperand) { + Debug.log("operand=%s", liveStateOperand); + return liveStateOperand; + } + }); } - }); + } + } + } + if (blockData.get(block).liveKill.get(operandNum)) { + definedIn.add(block); + try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { + for (LIRInstruction ins : ir.getLIRforBlock(block)) { + Debug.log("%d: %s", ins.id(), ins); + } } } } - } - if (blockData.get(block).liveKill.get(operandNum)) { - definedIn.add(block); - try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { - for (LIRInstruction ins : ir.lir(block)) { - Debug.log("%d: %s", ins.id(), ins); + + int[] hitCount = new int[numBlocks]; + + while (!definedIn.isEmpty()) { + AbstractBlock block = definedIn.removeFirst(); + usedIn.remove(block); + for (AbstractBlock successor : block.getSuccessors()) { + if (successor.isLoopHeader()) { + if (!block.isLoopEnd()) { + definedIn.add(successor); + } + } else { + if (++hitCount[successor.getId()] == successor.getPredecessorCount()) { + definedIn.add(successor); + } + } + } + } + try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) { + for (AbstractBlock block : usedIn) { + Debug.log("B%d", block.getId()); } } } } - - int[] hitCount = new int[numBlocks]; - - while (!definedIn.isEmpty()) { - AbstractBlock block = definedIn.removeFirst(); - usedIn.remove(block); - for (AbstractBlock successor : block.getSuccessors()) { - if (successor.isLoopHeader()) { - if (!block.isLoopEnd()) { - definedIn.add(successor); - } - } else { - if (++hitCount[successor.getId()] == successor.getPredecessorCount()) { - definedIn.add(successor); - } - } - } - } - try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) { - for (AbstractBlock block : usedIn) { - Debug.log("B%d", block.getId()); - } - } - indent2.outdent(); } - indent.outdent(); } } @@ -1147,140 +1151,142 @@ void buildIntervals() { - Indent indent = Debug.logAndIndent("build intervals"); + try (Indent indent = Debug.logAndIndent("build intervals")) { - intervalsSize = operandSize(); - intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY]; + intervalsSize = operandSize(); + intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY]; - // create a list with all caller-save registers (cpu, fpu, xmm) - Register[] callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters(); + // create a list with all caller-save registers (cpu, fpu, xmm) + Register[] callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters(); - // iterate all blocks in reverse order - for (int i = blockCount() - 1; i >= 0; i--) { - - AbstractBlock block = blockAt(i); - Indent indent2 = Debug.logAndIndent("handle block %d", block.getId()); + // iterate all blocks in reverse order + for (int i = blockCount() - 1; i >= 0; i--) { - List instructions = ir.lir(block); - final int blockFrom = getFirstLirInstructionId(block); - int blockTo = getLastLirInstructionId(block); + AbstractBlock block = blockAt(i); + try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) { - assert blockFrom == instructions.get(0).id(); - assert blockTo == instructions.get(instructions.size() - 1).id(); + List instructions = ir.getLIRforBlock(block); + final int blockFrom = getFirstLirInstructionId(block); + int blockTo = getLastLirInstructionId(block); - // Update intervals for operands live at the end of this block; - BitSet live = blockData.get(block).liveOut; - for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { - assert live.get(operandNum) : "should not stop here otherwise"; - AllocatableValue operand = operandFor(operandNum); - Debug.log("live in %d: %s", operandNum, operand); - - addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal); + assert blockFrom == instructions.get(0).id(); + assert blockTo == instructions.get(instructions.size() - 1).id(); - // add special use positions for loop-end blocks when the - // interval is used anywhere inside this loop. It's possible - // that the block was part of a non-natural loop, so it might - // have an invalid loop index. - if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().index)) { - intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); - } - } + // Update intervals for operands live at the end of this block; + BitSet live = blockData.get(block).liveOut; + for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { + assert live.get(operandNum) : "should not stop here otherwise"; + AllocatableValue operand = operandFor(operandNum); + Debug.log("live in %d: %s", operandNum, operand); - // iterate all instructions of the block in reverse order. - // definitions of intervals are processed before uses - for (int j = instructions.size() - 1; j >= 0; j--) { - final LIRInstruction op = instructions.get(j); - final int opId = op.id(); + addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal); - Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op); - - // add a temp range for each register if operation destroys caller-save registers - if (op.destroysCallerSavedRegisters()) { - for (Register r : callerSaveRegs) { - if (attributes(r).isAllocatable()) { - addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal); + // add special use positions for loop-end blocks when the + // interval is used anywhere inside this loop. It's possible + // that the block was part of a non-natural loop, so it might + // have an invalid loop index. + if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().index)) { + intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); } } - Debug.log("operation destroys all caller-save registers"); - } - op.forEachOutput(new ValueProcedure() { + // iterate all instructions of the block in reverse order. + // definitions of intervals are processed before uses + for (int j = instructions.size() - 1; j >= 0; j--) { + final LIRInstruction op = instructions.get(j); + final int opId = op.id(); + + try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, true); - } - return operand; - } - }); - op.forEachTemp(new ValueProcedure() { + // add a temp range for each register if operation destroys + // caller-save registers + if (op.destroysCallerSavedRegisters()) { + for (Register r : callerSaveRegs) { + if (attributes(r).isAllocatable()) { + addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal); + } + } + Debug.log("operation destroys all caller-save registers"); + } + + op.forEachOutput(new ValueProcedure() { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, false); - } - return operand; - } - }); - op.forEachAlive(new ValueProcedure() { + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, true); + } + return operand; + } + }); + op.forEachTemp(new ValueProcedure() { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, false); - } - return operand; - } - }); - op.forEachInput(new ValueProcedure() { + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, false); + } + return operand; + } + }); + op.forEachAlive(new ValueProcedure() { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, false); - } - return operand; - } - }); + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + RegisterPriority p = registerPriorityOfInputOperand(flags); + addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, false); + } + return operand; + } + }); + op.forEachInput(new ValueProcedure() { - // Add uses of live locals from interpreter's point of view for proper - // debug information generation - // Treat these operands as temp values (if the live range is extended - // to a call site, the value would be in a register at the call otherwise) - op.forEachState(new ValueProcedure() { + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + RegisterPriority p = registerPriorityOfInputOperand(flags); + addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, false); + } + return operand; + } + }); - @Override - public Value doValue(Value operand) { - addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind()); - return operand; - } - }); + // Add uses of live locals from interpreter's point of view for proper + // debug information generation + // Treat these operands as temp values (if the live range is extended + // to a call site, the value would be in a register at + // the call otherwise) + op.forEachState(new ValueProcedure() { - // special steps for some instructions (especially moves) - handleMethodArguments(op); + @Override + public Value doValue(Value operand) { + addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind()); + return operand; + } + }); - indent3.outdent(); + // special steps for some instructions (especially moves) + handleMethodArguments(op); - } // end of instruction iteration - indent2.outdent(); - } // end of block iteration + } - // add the range [0, 1] to all fixed intervals. - // the register allocator need not handle unhandled fixed intervals - for (Interval interval : intervals) { - if (interval != null && isRegister(interval.operand)) { - interval.addRange(0, 1); + } // end of instruction iteration + } + } // end of block iteration + + // add the range [0, 1] to all fixed intervals. + // the register allocator need not handle unhandled fixed intervals + for (Interval interval : intervals) { + if (interval != null && isRegister(interval.operand)) { + interval.addRange(0, 1); + } } } - indent.outdent(); } // * Phase 5: actual register allocation @@ -1432,19 +1438,19 @@ }; public void allocateRegisters() { - Indent indent = Debug.logAndIndent("allocate registers"); - Interval precoloredIntervals; - Interval notPrecoloredIntervals; + try (Indent indent = Debug.logAndIndent("allocate registers")) { + Interval precoloredIntervals; + Interval notPrecoloredIntervals; - Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL); - precoloredIntervals = result.first; - notPrecoloredIntervals = result.second; + Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL); + precoloredIntervals = result.first; + notPrecoloredIntervals = result.second; - // allocate cpu registers - LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); - lsw.walk(); - lsw.finishAllocation(); - indent.outdent(); + // allocate cpu registers + LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); + lsw.walk(); + lsw.finishAllocation(); + } } // * Phase 6: resolve data flow @@ -1510,7 +1516,7 @@ if (fromBlock.getSuccessorCount() <= 1) { Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId()); - List instructions = ir.lir(fromBlock); + List instructions = ir.getLIRforBlock(fromBlock); LIRInstruction instr = instructions.get(instructions.size() - 1); if (instr instanceof StandardOp.JumpOp) { // insert moves before branch @@ -1523,7 +1529,7 @@ Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId()); if (DetailedAsserts.getValue()) { - assert ir.lir(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; + assert ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; // because the number of predecessor edges matches the number of // successor edges, blocks which are reached by switch statements @@ -1534,7 +1540,7 @@ } } - moveResolver.setInsertPosition(ir.lir(toBlock), 1); + moveResolver.setInsertPosition(ir.getLIRforBlock(toBlock), 1); } } @@ -1543,69 +1549,71 @@ * have been split. */ void resolveDataFlow() { - Indent indent = Debug.logAndIndent("resolve data flow"); + try (Indent indent = Debug.logAndIndent("resolve data flow")) { - int numBlocks = blockCount(); - MoveResolver moveResolver = new MoveResolver(this); - BitSet blockCompleted = new BitSet(numBlocks); - BitSet alreadyResolved = new BitSet(numBlocks); + int numBlocks = blockCount(); + MoveResolver moveResolver = new MoveResolver(this); + BitSet blockCompleted = new BitSet(numBlocks); + BitSet alreadyResolved = new BitSet(numBlocks); + + for (AbstractBlock block : sortedBlocks) { - for (AbstractBlock block : sortedBlocks) { + // check if block has only one predecessor and only one successor + if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) { + List instructions = ir.getLIRforBlock(block); + assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; + assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; - // check if block has only one predecessor and only one successor - if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) { - List instructions = ir.lir(block); - assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; - assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; + // check if block is empty (only label and branch) + if (instructions.size() == 2) { + AbstractBlock pred = block.getPredecessors().iterator().next(); + AbstractBlock sux = block.getSuccessors().iterator().next(); + + // prevent optimization of two consecutive blocks + if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) { + Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId()); + + blockCompleted.set(block.getLinearScanNumber()); - // check if block is empty (only label and branch) - if (instructions.size() == 2) { - AbstractBlock pred = block.getPredecessors().iterator().next(); - AbstractBlock sux = block.getSuccessors().iterator().next(); - - // prevent optimization of two consecutive blocks - if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) { - Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId()); + // directly resolve between pred and sux (without looking + // at the empty block + // between) + resolveCollectMappings(pred, sux, moveResolver); + if (moveResolver.hasMappings()) { + moveResolver.setInsertPosition(instructions, 1); + moveResolver.resolveAndAppendMoves(); + } + } + } + } + } - blockCompleted.set(block.getLinearScanNumber()); + for (AbstractBlock fromBlock : sortedBlocks) { + if (!blockCompleted.get(fromBlock.getLinearScanNumber())) { + alreadyResolved.clear(); + alreadyResolved.or(blockCompleted); + + for (AbstractBlock toBlock : fromBlock.getSuccessors()) { - // directly resolve between pred and sux (without looking at the empty block - // between) - resolveCollectMappings(pred, sux, moveResolver); - if (moveResolver.hasMappings()) { - moveResolver.setInsertPosition(instructions, 1); - moveResolver.resolveAndAppendMoves(); + // check for duplicate edges between the same blocks (can happen with switch + // blocks) + if (!alreadyResolved.get(toBlock.getLinearScanNumber())) { + Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId()); + + alreadyResolved.set(toBlock.getLinearScanNumber()); + + // collect all intervals that have been split between + // fromBlock and toBlock + resolveCollectMappings(fromBlock, toBlock, moveResolver); + if (moveResolver.hasMappings()) { + resolveFindInsertPos(fromBlock, toBlock, moveResolver); + moveResolver.resolveAndAppendMoves(); + } } } } } } - - for (AbstractBlock fromBlock : sortedBlocks) { - if (!blockCompleted.get(fromBlock.getLinearScanNumber())) { - alreadyResolved.clear(); - alreadyResolved.or(blockCompleted); - - for (AbstractBlock toBlock : fromBlock.getSuccessors()) { - - // check for duplicate edges between the same blocks (can happen with switch - // blocks) - if (!alreadyResolved.get(toBlock.getLinearScanNumber())) { - Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId()); - - alreadyResolved.set(toBlock.getLinearScanNumber()); - - // collect all intervals that have been split between fromBlock and toBlock - resolveCollectMappings(fromBlock, toBlock, moveResolver); - if (moveResolver.hasMappings()) { - resolveFindInsertPos(fromBlock, toBlock, moveResolver); - moveResolver.resolveAndAppendMoves(); - } - } - } - } - } - indent.outdent(); } // * Phase 7: assign register numbers back to LIR @@ -1618,7 +1626,7 @@ /** * Assigns the allocated location for an LIR instruction operand back into the instruction. - * + * * @param operand an LIR instruction operand * @param opId the id of the LIR instruction using {@code operand} * @param mode the usage mode for {@code operand} by the instruction @@ -1636,7 +1644,7 @@ // before the branch instruction. So the split child information for this branch // would // be incorrect. - LIRInstruction instr = ir.lir(block).get(ir.lir(block).size() - 1); + LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1); if (instr instanceof StandardOp.JumpOp) { if (blockData.get(block).liveOut.get(operandNumber(operand))) { assert false : "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow)"; @@ -1752,7 +1760,7 @@ // are not // considered in the live ranges of intervals) // Solution: use the first opId of the branch target block instead. - final LIRInstruction instr = ir.lir(block).get(ir.lir(block).size() - 1); + final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1); if (instr instanceof StandardOp.JumpOp) { if (blockData.get(block).liveOut.get(operandNumber(operand))) { tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next()); @@ -1846,7 +1854,7 @@ try (Indent indent = Debug.logAndIndent("assign locations")) { for (AbstractBlock block : sortedBlocks) { try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) { - assignLocations(ir.lir(block), iw); + assignLocations(ir.getLIRforBlock(block), iw); } } } @@ -1857,57 +1865,57 @@ /* * This is the point to enable debug logging for the whole register allocation. */ - Indent indent = Debug.logAndIndent("LinearScan allocate"); - - try (Scope s = Debug.scope("LifetimeAnalysis")) { - numberInstructions(); - printLir("Before register allocation", true); - computeLocalLiveSets(); - computeGlobalLiveSets(); - buildIntervals(); - sortIntervalsBeforeAllocation(); - } catch (Throwable e) { - throw Debug.handle(e); - } + try (Indent indent = Debug.logAndIndent("LinearScan allocate")) { - try (Scope s = Debug.scope("RegisterAllocation")) { - printIntervals("Before register allocation"); - allocateRegisters(); - } catch (Throwable e) { - throw Debug.handle(e); - } + try (Scope s = Debug.scope("LifetimeAnalysis")) { + numberInstructions(); + printLir("Before register allocation", true); + computeLocalLiveSets(); + computeGlobalLiveSets(); + buildIntervals(); + sortIntervalsBeforeAllocation(); + } catch (Throwable e) { + throw Debug.handle(e); + } - try (Scope s = Debug.scope("ResolveDataFlow")) { - resolveDataFlow(); - } catch (Throwable e) { - throw Debug.handle(e); - } + try (Scope s = Debug.scope("RegisterAllocation")) { + printIntervals("Before register allocation"); + allocateRegisters(); + } catch (Throwable e) { + throw Debug.handle(e); + } - try (Scope s = Debug.scope("DebugInfo")) { - frameMap.finish(); - - printIntervals("After register allocation"); - printLir("After register allocation", true); - - sortIntervalsAfterAllocation(); - - if (DetailedAsserts.getValue()) { - verify(); + try (Scope s = Debug.scope("ResolveDataFlow")) { + resolveDataFlow(); + } catch (Throwable e) { + throw Debug.handle(e); } - eliminateSpillMoves(); - assignLocations(); + try (Scope s = Debug.scope("DebugInfo")) { + frameMap.finish(); + + printIntervals("After register allocation"); + printLir("After register allocation", true); + + sortIntervalsAfterAllocation(); - if (DetailedAsserts.getValue()) { - verifyIntervals(); + if (DetailedAsserts.getValue()) { + verify(); + } + + eliminateSpillMoves(); + assignLocations(); + + if (DetailedAsserts.getValue()) { + verifyIntervals(); + } + } catch (Throwable e) { + throw Debug.handle(e); } - } catch (Throwable e) { - throw Debug.handle(e); - } - printLir("After register number assignment", true); + printLir("After register number assignment", true); - indent.outdent(); + } } void printIntervals(String label) { @@ -2060,7 +2068,7 @@ IntervalWalker iw = new IntervalWalker(this, fixedIntervals, otherIntervals); for (AbstractBlock block : sortedBlocks) { - List instructions = ir.lir(block); + List instructions = ir.getLIRforBlock(block); for (int j = 0; j < instructions.size(); j++) { LIRInstruction op = instructions.get(j); @@ -2114,7 +2122,7 @@ /** * Returns a value for a interval definition, which can be used for re-materialization. - * + * * @param op An instruction which defines a value * @param operand The destination operand of the instruction * @param interval The interval for this defined value. diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Sun Mar 30 16:08:33 2014 +0200 @@ -53,6 +53,14 @@ private MoveResolver moveResolver; // for ordering spill moves + /** + * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used, + * they can grow quite long. The maximum length observed was 45 (all numbers taken from a + * bootstrap run of Graal). Therefore, we initialize {@link #spillIntervals} with this marker + * value, and allocate a "real" list only on demand in {@link #setUsePos}. + */ + private static final List EMPTY_LIST = new ArrayList<>(0); + // accessors mapped to same functions in class LinearScan int blockCount() { return allocator.blockCount(); @@ -70,16 +78,13 @@ super(allocator, unhandledFixedFirst, unhandledAnyFirst); // If all allocatable registers are caller saved, then no registers are live across a call - // site. - // The register allocator can save time not trying to find a register at a call site. - HashSet registers = new HashSet<>(Arrays.asList(allocator.frameMap.registerConfig.getAllocatableRegisters())); - registers.removeAll(Arrays.asList(allocator.frameMap.registerConfig.getCallerSaveRegisters())); - allocator.callKillsRegisters = registers.size() == 0; + // site. The register allocator can save time not trying to find a register at a call site. + allocator.callKillsRegisters = allocator.frameMap.registerConfig.areAllAllocatableRegistersCallerSaved(); moveResolver = new MoveResolver(allocator); spillIntervals = Util.uncheckedCast(new List[allocator.registers.length]); for (int i = 0; i < allocator.registers.length; i++) { - spillIntervals[i] = new ArrayList<>(2); + spillIntervals[i] = EMPTY_LIST; } usePos = new int[allocator.registers.length]; blockPos = new int[allocator.registers.length]; @@ -114,7 +119,12 @@ this.usePos[i] = usePos; } if (!onlyProcessUsePos) { - spillIntervals[i].add(interval); + List list = spillIntervals[i]; + if (list == EMPTY_LIST) { + list = new ArrayList<>(2); + spillIntervals[i] = list; + } + list.add(interval); } } } @@ -244,7 +254,7 @@ // numbering of instructions is known. // When the block already contains spill moves, the index must be increased until the // correct index is reached. - List instructions = allocator.ir.lir(opBlock); + List instructions = allocator.ir.getLIRforBlock(opBlock); int index = (opId - instructions.get(0).id()) >> 1; assert instructions.get(index).id() <= opId : "error in calculation"; @@ -440,82 +450,82 @@ int maxSplitPos = currentPosition; int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos) + 1, interval.from()); - Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos); + try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) { - assert interval.state == State.Active : "why spill interval that is not active?"; - assert interval.from() <= minSplitPos : "cannot split before start of interval"; - assert minSplitPos <= maxSplitPos : "invalid order"; - assert maxSplitPos < interval.to() : "cannot split at end end of interval"; - assert currentPosition < interval.to() : "interval must not end before current position"; + assert interval.state == State.Active : "why spill interval that is not active?"; + assert interval.from() <= minSplitPos : "cannot split before start of interval"; + assert minSplitPos <= maxSplitPos : "invalid order"; + assert maxSplitPos < interval.to() : "cannot split at end end of interval"; + assert currentPosition < interval.to() : "interval must not end before current position"; + + if (minSplitPos == interval.from()) { + // the whole interval is never used, so spill it entirely to memory - if (minSplitPos == interval.from()) { - // the whole interval is never used, so spill it entirely to memory + try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) { - try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) { + assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition"; + + allocator.assignSpillSlot(interval); + allocator.changeSpillState(interval, minSplitPos); - assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition"; - - allocator.assignSpillSlot(interval); - allocator.changeSpillState(interval, minSplitPos); + // Also kick parent intervals out of register to memory when they have no use + // position. This avoids short interval in register surrounded by intervals in + // memory . avoid useless moves from memory to register and back + Interval parent = interval; + while (parent != null && parent.isSplitChild()) { + parent = parent.getSplitChildBeforeOpId(parent.from()); - // Also kick parent intervals out of register to memory when they have no use - // position. This avoids short interval in register surrounded by intervals in - // memory . avoid useless moves from memory to register and back - Interval parent = interval; - while (parent != null && parent.isSplitChild()) { - parent = parent.getSplitChildBeforeOpId(parent.from()); + if (isRegister(parent.location())) { + if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) { + // parent is never used, so kick it out of its assigned register + Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber); + allocator.assignSpillSlot(parent); + } else { + // do not go further back because the register is actually used by + // the interval + parent = null; + } + } + } + } + + } else { + // search optimal split pos, split interval and spill only the right hand part + int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false); + + assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; + assert optimalSplitPos < interval.to() : "cannot split at end of interval"; + assert optimalSplitPos >= interval.from() : "cannot split before start of interval"; - if (isRegister(parent.location())) { - if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) { - // parent is never used, so kick it out of its assigned register - Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber); - allocator.assignSpillSlot(parent); - } else { - // do not go further back because the register is actually used by - // the interval - parent = null; - } + if (!allocator.isBlockBegin(optimalSplitPos)) { + // move position before actual instruction (odd opId) + optimalSplitPos = (optimalSplitPos - 1) | 1; + } + + try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) { + assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary"; + assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary"; + + Interval spilledPart = interval.split(optimalSplitPos, allocator); + allocator.assignSpillSlot(spilledPart); + allocator.changeSpillState(spilledPart, optimalSplitPos); + + if (!allocator.isBlockBegin(optimalSplitPos)) { + Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber); + insertMove(optimalSplitPos, interval, spilledPart); + } + + // the currentSplitChild is needed later when moves are inserted for reloading + assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild"; + spilledPart.makeCurrentSplitChild(); + + if (Debug.isLogEnabled()) { + Debug.log("left interval: %s", interval.logString(allocator)); + Debug.log("spilled interval : %s", spilledPart.logString(allocator)); } } } - - } else { - // search optimal split pos, split interval and spill only the right hand part - int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false); - - assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; - assert optimalSplitPos < interval.to() : "cannot split at end of interval"; - assert optimalSplitPos >= interval.from() : "cannot split before start of interval"; - - if (!allocator.isBlockBegin(optimalSplitPos)) { - // move position before actual instruction (odd opId) - optimalSplitPos = (optimalSplitPos - 1) | 1; - } - - try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) { - assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary"; - assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary"; - - Interval spilledPart = interval.split(optimalSplitPos, allocator); - allocator.assignSpillSlot(spilledPart); - allocator.changeSpillState(spilledPart, optimalSplitPos); - - if (!allocator.isBlockBegin(optimalSplitPos)) { - Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber); - insertMove(optimalSplitPos, interval, spilledPart); - } - - // the currentSplitChild is needed later when moves are inserted for reloading - assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild"; - spilledPart.makeCurrentSplitChild(); - - if (Debug.isLogEnabled()) { - Debug.log("left interval: %s", interval.logString(allocator)); - Debug.log("spilled interval : %s", spilledPart.logString(allocator)); - } - } } - indent.outdent(); } void splitStackInterval(Interval interval) { @@ -830,52 +840,52 @@ Interval interval = currentInterval; boolean result = true; - Indent indent = Debug.logAndIndent("activating interval %s, splitParent: %d", interval, interval.splitParent().operandNumber); + try (Indent indent = Debug.logAndIndent("activating interval %s, splitParent: %d", interval, interval.splitParent().operandNumber)) { - final Value operand = interval.operand; - if (interval.location() != null && isStackSlot(interval.location())) { - // activating an interval that has a stack slot assigned . split it at first use - // position - // used for method parameters - Debug.log("interval has spill slot assigned (method parameter) . split it before first use"); - splitStackInterval(interval); - result = false; + final Value operand = interval.operand; + if (interval.location() != null && isStackSlot(interval.location())) { + // activating an interval that has a stack slot assigned . split it at first use + // position + // used for method parameters + Debug.log("interval has spill slot assigned (method parameter) . split it before first use"); + splitStackInterval(interval); + result = false; - } else { - if (interval.location() == null) { - // interval has not assigned register . normal allocation - // (this is the normal case for most intervals) - Debug.log("normal allocation of register"); + } else { + if (interval.location() == null) { + // interval has not assigned register . normal allocation + // (this is the normal case for most intervals) + Debug.log("normal allocation of register"); - // assign same spill slot to non-intersecting intervals - combineSpilledIntervals(interval); + // assign same spill slot to non-intersecting intervals + combineSpilledIntervals(interval); - initVarsForAlloc(interval); - if (noAllocationPossible(interval) || !allocFreeRegister(interval)) { - // no empty register available. - // split and spill another interval so that this interval gets a register - allocLockedRegister(interval); - } + initVarsForAlloc(interval); + if (noAllocationPossible(interval) || !allocFreeRegister(interval)) { + // no empty register available. + // split and spill another interval so that this interval gets a register + allocLockedRegister(interval); + } - // spilled intervals need not be move to active-list - if (!isRegister(interval.location())) { - result = false; + // spilled intervals need not be move to active-list + if (!isRegister(interval.location())) { + result = false; + } } } - } - // load spilled values that become active from stack slot to register - if (interval.insertMoveWhenActivated()) { - assert interval.isSplitChild(); - assert interval.currentSplitChild() != null; - assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval"; - Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); + // load spilled values that become active from stack slot to register + if (interval.insertMoveWhenActivated()) { + assert interval.isSplitChild(); + assert interval.currentSplitChild() != null; + assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval"; + Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); - insertMove(interval.from(), interval.currentSplitChild(), interval); + insertMove(interval.from(), interval.currentSplitChild(), interval); + } + interval.makeCurrentSplitChild(); + } - interval.makeCurrentSplitChild(); - - indent.outdent(); return result; // true = interval is moved to active list } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Sun Mar 30 16:08:33 2014 +0200 @@ -106,7 +106,7 @@ } // process all operations of the block - processOperations(allocator.ir.lir(block), inputState); + processOperations(allocator.ir.getLIRforBlock(block), inputState); // iterate all successors for (AbstractBlock succ : block.getSuccessors()) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/BytecodeParser.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, 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.compiler.gen; + +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.cfg.*; + +public interface BytecodeParser> { + void processBlock(T block); + + void setParameter(int i, Variable emitMove); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Sun Mar 30 16:08:33 2014 +0200 @@ -89,7 +89,7 @@ if (!currentField.fieldValues().get(i).isConstant() || currentField.fieldValues().get(i).asConstant().getKind() != Kind.Illegal) { values[pos++] = toValue(currentField.fieldValues().get(i)); } else { - assert currentField.fieldValues().get(i - 1).kind() == Kind.Double || currentField.fieldValues().get(i - 1).kind() == Kind.Long : vobj + " " + i + " " + + assert currentField.fieldValues().get(i - 1).getKind() == Kind.Double || currentField.fieldValues().get(i - 1).getKind() == Kind.Long : vobj + " " + i + " " + currentField.fieldValues().get(i - 1); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResult.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, 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.compiler.gen; + +import com.oracle.graal.lir.*; + +public interface LIRGenerationResult { + FrameMap getFrameMap(); + + LIR getLIR(); + + boolean hasForeignCall(); + + void setForeignCall(boolean b); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResultBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerationResultBase.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 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.compiler.gen; + +import com.oracle.graal.lir.*; + +public class LIRGenerationResultBase implements LIRGenerationResult { + private final LIR lir; + private final FrameMap frameMap; + /** + * Records whether the code being generated makes at least one foreign call. + */ + private boolean hasForeignCall; + + public LIRGenerationResultBase(LIR lir, FrameMap frameMap) { + this.lir = lir; + this.frameMap = frameMap; + } + + public LIR getLIR() { + return lir; + } + + /** + * Determines whether the code being generated makes at least one foreign call. + */ + public boolean hasForeignCall() { + return hasForeignCall; + } + + public final void setForeignCall(boolean hasForeignCall) { + this.hasForeignCall = hasForeignCall; + } + + public final FrameMap getFrameMap() { + return frameMap; + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,38 +26,31 @@ import static com.oracle.graal.api.meta.Value.*; import static com.oracle.graal.lir.LIR.*; import static com.oracle.graal.lir.LIRValueUtil.*; -import static com.oracle.graal.nodes.ConstantNode.*; import static com.oracle.graal.phases.GraalOptions.*; import java.util.*; -import java.util.Map.Entry; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.BlockEndOp; -import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.StandardOp.LabelOp; import com.oracle.graal.lir.StandardOp.NoOp; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.util.*; /** * This class traverses the HIR instructions and generates LIR instructions from them. */ -public abstract class LIRGenerator implements LIRGeneratorTool, LIRTypeTool { +public abstract class LIRGenerator implements ArithmeticLIRGenerator, LIRGeneratorTool, LIRTypeTool { public static class Options { // @formatter:off @@ -68,16 +61,12 @@ // @formatter:on } - public final FrameMap frameMap; - public final NodeMap nodeOperands; - public final LIR lir; + private final Providers providers; + private final CallingConvention cc; - private final Providers providers; - protected final CallingConvention cc; + private DebugInfoBuilder debugInfoBuilder; - protected final DebugInfoBuilder debugInfoBuilder; - - protected Block currentBlock; + protected AbstractBlock currentBlock; private final int traceLevel; private final boolean printIRWithLIR; @@ -103,12 +92,12 @@ * The block that does or will contain {@link #op}. This is initially the block where the * first usage of the constant is seen during LIR generation. */ - private Block block; + Block block; /** * The variable into which the constant is loaded. */ - private final Variable variable; + final Variable variable; public LoadConstant(Variable variable, Block block, int index, LIRInstruction op) { this.variable = variable; @@ -143,40 +132,40 @@ if (index >= 0) { // Replace the move with a filler op so that the operation // list does not need to be adjusted. - List instructions = lir.lir(block); + List instructions = lir.getLIRforBlock(block); instructions.set(index, new NoOp(null, -1)); index = -1; } } } - private Map constantLoads; + Map constantLoads; - private ValueNode currentInstruction; - private ValueNode lastInstructionPrinted; // Debugging only + protected LIRGenerationResult res; /** - * Records whether the code being generated makes at least one foreign call. + * Set this before using the LIRGenerator. + * + * TODO this should be removed */ - private boolean hasForeignCall; + void setDebugInfoBuilder(DebugInfoBuilder builder) { + debugInfoBuilder = builder; + } /** * Checks whether the supplied constant can be used without loading it into a register for store * operations, i.e., on the right hand side of a memory access. - * + * * @param c The constant to check. * @return True if the constant can be used directly, false if the constant needs to be in a * register. */ public abstract boolean canStoreConstant(Constant c, boolean isCompressed); - public LIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { + public LIRGenerator(Providers providers, CallingConvention cc, LIRGenerationResult res) { + this.res = res; this.providers = providers; - this.frameMap = frameMap; this.cc = cc; - this.nodeOperands = graph.createNodeMap(); - this.lir = lir; - this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands); this.traceLevel = Options.TraceLIRGeneratorLevel.getValue(); this.printIRWithLIR = Options.PrintIRWithLIR.getValue(); } @@ -189,17 +178,12 @@ return true; } - @SuppressWarnings("hiding") - protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { - return new DebugInfoBuilder(nodeOperands); - } - @Override public TargetDescription target() { return getCodeCache().getTarget(); } - protected Providers getProviders() { + public Providers getProviders() { return providers; } @@ -219,100 +203,19 @@ } /** - * Determines whether the code being generated makes at least one foreign call. - */ - public boolean hasForeignCall() { - return hasForeignCall; - } - - /** - * Returns the operand that has been previously initialized by - * {@link #setResult(ValueNode, Value)} with the result of an instruction. - * - * @param node A node that produces a result value. - */ - @Override - public Value operand(ValueNode node) { - if (nodeOperands == null) { - return null; - } - Value operand = nodeOperands.get(node); - if (operand == null) { - return getConstantOperand(node); - } - return operand; - } - - private Value getConstantOperand(ValueNode node) { - if (!ConstantNodeRecordsUsages) { - Constant value = node.asConstant(); - if (value != null) { - if (canInlineConstant(value)) { - return setResult(node, value); - } else { - Variable loadedValue; - if (constantLoads == null) { - constantLoads = new HashMap<>(); - } - LoadConstant load = constantLoads.get(value); - if (load == null) { - int index = lir.lir(currentBlock).size(); - loadedValue = emitMove(value); - LIRInstruction op = lir.lir(currentBlock).get(index); - constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op)); - } else { - Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock); - loadedValue = load.variable; - if (dominator != load.block) { - load.unpin(lir); - } else { - assert load.block != currentBlock || load.index < lir.lir(currentBlock).size(); - } - load.block = dominator; - } - return loadedValue; - } - } - } else { - // Constant is loaded by ConstantNode.generate() - } - return null; - } - - public ValueNode valueForOperand(Value value) { - for (Entry entry : nodeOperands.entries()) { - if (entry.getValue().equals(value)) { - return (ValueNode) entry.getKey(); - } - } - return null; - } - - /** * Creates a new {@linkplain Variable variable}. - * + * * @param platformKind The kind of the new variable. * @return a new variable */ @Override public Variable newVariable(PlatformKind platformKind) { - return new Variable(platformKind, lir.nextVariable()); + return new Variable(platformKind, res.getLIR().nextVariable()); } @Override public RegisterAttributes attributes(Register register) { - return frameMap.registerConfig.getAttributesMap()[register.number]; - } - - @Override - public Value setResult(ValueNode x, Value operand) { - assert (!isRegister(operand) || !attributes(asRegister(operand)).isAllocatable()); - assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice"; - assert operand != null && isLegal(operand) : "operand must be legal"; - assert operand.getKind().getStackKind() == x.kind() || x.kind() == Kind.Illegal : operand.getKind().getStackKind() + " must match " + x.kind(); - assert !(x instanceof VirtualObjectNode); - nodeOperands.set(x, operand); - return operand; + return res.getFrameMap().registerConfig.getAttributesMap()[register.number]; } @Override @@ -341,11 +244,13 @@ } public LabelRef getLIRBlock(FixedNode b) { - Block result = lir.getControlFlowGraph().blockFor(b); + assert res.getLIR().getControlFlowGraph() instanceof ControlFlowGraph; + Block result = ((ControlFlowGraph) res.getLIR().getControlFlowGraph()).blockFor(b); int suxIndex = currentBlock.getSuccessors().indexOf(result); assert suxIndex != -1 : "Block not in successor list of current block"; - return LabelRef.forSuccessor(lir, currentBlock, suxIndex); + assert currentBlock instanceof Block; + return LabelRef.forSuccessor(res.getLIR(), (Block) currentBlock, suxIndex); } /** @@ -355,18 +260,31 @@ return false; } + private static FrameState getFrameState(DeoptimizingNode deopt) { + if (deopt instanceof DeoptimizingNode.DeoptBefore) { + assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter); + return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore(); + } else if (deopt instanceof DeoptimizingNode.DeoptDuring) { + assert !(deopt instanceof DeoptimizingNode.DeoptAfter); + return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring(); + } else { + assert deopt instanceof DeoptimizingNode.DeoptAfter; + return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter(); + } + } + public LIRFrameState state(DeoptimizingNode deopt) { if (!deopt.canDeoptimize()) { return null; } - return stateFor(deopt.getDeoptimizationState()); + return stateFor(getFrameState(deopt)); } public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) { if (!deopt.canDeoptimize()) { return null; } - return stateForWithExceptionEdge(deopt.getDeoptimizationState(), exceptionEdge); + return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge); } public LIRFrameState stateFor(FrameState state) { @@ -378,12 +296,12 @@ return new LIRFrameState(null, null, null); } assert state != null; - return debugInfoBuilder.build(state, exceptionEdge); + return getDebugInfoBuilder().build(state, exceptionEdge); } /** * Gets the ABI specific operand used to return a value of a given kind from a method. - * + * * @param kind the kind of value being returned * @return the operand representing the ABI defined location used return a value of kind * {@code kind} @@ -392,24 +310,24 @@ if (kind == Kind.Void) { return ILLEGAL; } - return frameMap.registerConfig.getReturnRegister(kind).asValue(kind); + return res.getFrameMap().registerConfig.getReturnRegister(kind).asValue(kind); } public void append(LIRInstruction op) { if (printIRWithLIR && !TTY.isSuppressed()) { - if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { - lastInstructionPrinted = currentInstruction; - InstructionPrinter ip = new InstructionPrinter(TTY.out()); - ip.printInstructionListing(currentInstruction); - } + // if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { + // lastInstructionPrinted = currentInstruction; + // InstructionPrinter ip = new InstructionPrinter(TTY.out()); + // ip.printInstructionListing(currentInstruction); + // } TTY.println(op.toStringWithIdPrefix()); TTY.println(); } assert LIRVerifier.verify(op); - lir.lir(currentBlock).add(op); + res.getLIR().getLIRforBlock(currentBlock).add(op); } - public void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap) { + public final void doBlockStart(AbstractBlock block) { if (printIRWithLIR) { TTY.print(block.toString()); } @@ -417,63 +335,17 @@ currentBlock = block; // set up the list of LIR instructions - assert lir.lir(block) == null : "LIR list already computed for this block"; - lir.setLir(block, new ArrayList()); + assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block"; + res.getLIR().setLIRforBlock(block, new ArrayList()); append(new LabelOp(new Label(block.getId()), block.isAligned())); if (traceLevel >= 1) { TTY.println("BEGIN Generating LIR for block B" + block.getId()); } - - if (block == lir.getControlFlowGraph().getStartBlock()) { - assert block.getPredecessorCount() == 0; - emitPrologue(graph); - } else { - assert block.getPredecessorCount() > 0; - } + } - List nodes = blockMap.get(block); - for (int i = 0; i < nodes.size(); i++) { - Node instr = nodes.get(i); - if (traceLevel >= 3) { - TTY.println("LIRGen for " + instr); - } - if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) { - // Loading of constants is done lazily by operand() - } else if (instr instanceof ValueNode) { - ValueNode valueNode = (ValueNode) instr; - if (operand(valueNode) == null) { - if (!peephole(valueNode)) { - try { - doRoot((ValueNode) instr); - } catch (GraalInternalError e) { - throw e.addContext(instr); - } catch (Throwable e) { - throw new GraalInternalError(e).addContext(instr); - } - } - } else { - // There can be cases in which the result of an instruction is already set - // before by other instructions. - } - } - } - - if (!hasBlockEnd(block)) { - NodeClassIterable successors = block.getEndNode().successors(); - assert successors.count() == block.getSuccessorCount(); - if (block.getSuccessorCount() != 1) { - /* - * If we have more than one successor, we cannot just use the first one. Since - * successors are unordered, this would be a random choice. - */ - throw new GraalInternalError("Block without BlockEndOp: " + block.getEndNode()); - } - emitJump(getLIRBlock((FixedNode) successors.first())); - } - - assert verifyBlock(lir, block); + public final void doBlockEnd(AbstractBlock block) { if (traceLevel >= 1) { TTY.println("END Generating LIR for block B" + block.getId()); @@ -486,188 +358,12 @@ } } - protected abstract boolean peephole(ValueNode valueNode); - - private boolean hasBlockEnd(Block block) { - List ops = lir.lir(block); - if (ops.size() == 0) { - return false; - } - return ops.get(ops.size() - 1) instanceof BlockEndOp; - } - - private void doRoot(ValueNode instr) { - if (traceLevel >= 2) { - TTY.println("Emitting LIR for instruction " + instr); - } - currentInstruction = instr; - - Debug.log("Visiting %s", instr); - emitNode(instr); - Debug.log("Operand for %s = %s", instr, operand(instr)); - } - - protected void emitNode(ValueNode node) { - if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) { - Debug.log("This node has invalid type, we are emitting dead code(?): %s", node); - } - if (node instanceof LIRGenLowerable) { - ((LIRGenLowerable) node).generate(this); - } else if (node instanceof LIRLowerable) { - ((LIRLowerable) node).generate(this); - } else if (node instanceof ArithmeticLIRLowerable) { - ((ArithmeticLIRLowerable) node).generate(this); - } else { - throw GraalInternalError.shouldNotReachHere("node is not LIRLowerable: " + node); - } - } - - protected void emitPrologue(StructuredGraph graph) { - CallingConvention incomingArguments = cc; - - Value[] params = new Value[incomingArguments.getArgumentCount()]; - for (int i = 0; i < params.length; i++) { - params[i] = toStackKind(incomingArguments.getArgument(i)); - if (ValueUtil.isStackSlot(params[i])) { - StackSlot slot = ValueUtil.asStackSlot(params[i]); - if (slot.isInCallerFrame() && !lir.hasArgInCallerFrame()) { - lir.setHasArgInCallerFrame(); - } - } - } - - emitIncomingValues(params); - - for (ParameterNode param : graph.getNodes(ParameterNode.class)) { - Value paramValue = params[param.index()]; - assert paramValue.getKind() == param.kind().getStackKind(); - setResult(param, emitMove(paramValue)); - } - } - public void emitIncomingValues(Value[] params) { - ((LabelOp) lir.lir(currentBlock).get(0)).setIncomingValues(params); - } - - @Override - public void visitReturn(ReturnNode x) { - AllocatableValue operand = ILLEGAL; - if (x.result() != null) { - operand = resultOperandFor(x.result().kind()); - emitMove(operand, operand(x.result())); - } - emitReturn(operand); - } - - protected abstract void emitReturn(Value input); - - @Override - public void visitMerge(MergeNode x) { - } - - @Override - public void visitEndNode(AbstractEndNode end) { - moveToPhi(end.merge(), end); - } - - /** - * Runtime specific classes can override this to insert a safepoint at the end of a loop. - */ - @Override - public void visitLoopEnd(LoopEndNode x) { - } - - private void moveToPhi(MergeNode merge, AbstractEndNode pred) { - if (traceLevel >= 1) { - TTY.println("MOVE TO PHI from " + pred + " to " + merge); - } - PhiResolver resolver = new PhiResolver(this); - for (PhiNode phi : merge.phis()) { - if (phi.type() == PhiType.Value) { - ValueNode curVal = phi.valueAt(pred); - resolver.move(operandForPhi(phi), operand(curVal)); - } - } - resolver.dispose(); - - append(new JumpOp(getLIRBlock(merge))); + ((LabelOp) res.getLIR().getLIRforBlock(currentBlock).get(0)).setIncomingValues(params); } protected PlatformKind getPhiKind(PhiNode phi) { - return phi.kind(); - } - - private Value operandForPhi(PhiNode phi) { - assert phi.type() == PhiType.Value : "wrong phi type: " + phi; - Value result = operand(phi); - if (result == null) { - // allocate a variable for this phi - Variable newOperand = newVariable(getPhiKind(phi)); - setResult(phi, newOperand); - return newOperand; - } else { - return result; - } - } - - @Override - public void emitIf(IfNode x) { - emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); - } - - public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { - if (node instanceof IsNullNode) { - emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); - } else if (node instanceof CompareNode) { - emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); - } else if (node instanceof LogicConstantNode) { - emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor); - } else if (node instanceof IntegerTestNode) { - emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); - } else { - throw GraalInternalError.unimplemented(node.toString()); - } - } - - private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { - emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability); - } - - public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { - emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); - } - - public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { - emitIntegerTestBranch(operand(test.x()), operand(test.y()), trueSuccessor, falseSuccessor, trueSuccessorProbability); - } - - public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { - LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock; - emitJump(block); - } - - @Override - public void emitConditional(ConditionalNode conditional) { - Value tVal = operand(conditional.trueValue()); - Value fVal = operand(conditional.falseValue()); - setResult(conditional, emitConditional(conditional.condition(), tVal, fVal)); - } - - public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) { - if (node instanceof IsNullNode) { - IsNullNode isNullNode = (IsNullNode) node; - return emitConditionalMove(operand(isNullNode.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueValue, falseValue); - } else if (node instanceof CompareNode) { - CompareNode compare = (CompareNode) node; - return emitConditionalMove(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue); - } else if (node instanceof LogicConstantNode) { - return emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue); - } else if (node instanceof IntegerTestNode) { - IntegerTestNode test = (IntegerTestNode) node; - return emitIntegerTestMove(operand(test.x()), operand(test.y()), trueValue, falseValue); - } else { - throw GraalInternalError.unimplemented(node.toString()); - } + return phi.getKind(); } public abstract void emitJump(LabelRef label); @@ -682,42 +378,6 @@ public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue); - @Override - public void emitInvoke(Invoke x) { - LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget(); - CallingConvention invokeCc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(getMetaAccess()), callTarget.signature(), target(), false); - frameMap.callsMethod(invokeCc); - - Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments()); - - LabelRef exceptionEdge = null; - if (x instanceof InvokeWithExceptionNode) { - exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()); - } - LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge); - - Value result = invokeCc.getReturn(); - if (callTarget instanceof DirectCallTargetNode) { - emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); - } else if (callTarget instanceof IndirectCallTargetNode) { - emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); - } else { - throw GraalInternalError.shouldNotReachHere(); - } - - if (isLegal(result)) { - setResult(x.asNode(), emitMove(result)); - } - - if (x instanceof InvokeWithExceptionNode) { - emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next())); - } - } - - protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); - - protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); - protected abstract void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info); protected static AllocatableValue toStackKind(AllocatableValue value) { @@ -735,29 +395,12 @@ return value; } - public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection arguments) { - // for each argument, load it into the correct location - Value[] result = new Value[arguments.size()]; - int j = 0; - for (ValueNode arg : arguments) { - if (arg != null) { - AllocatableValue operand = toStackKind(invokeCc.getArgument(j)); - emitMove(operand, operand(arg)); - result[j] = operand; - j++; - } else { - throw GraalInternalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types..."); - } - } - return result; - } - @Override public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) { LIRFrameState state = null; if (linkage.canDeoptimize()) { if (info != null) { - state = stateFor(info.getDeoptimizationState()); + state = stateFor(getFrameState(info)); } else { assert needOnlyOopMaps(); state = new LIRFrameState(null, null, null); @@ -766,7 +409,7 @@ // move the arguments into the correct location CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); - frameMap.callsMethod(linkageCc); + res.getFrameMap().callsMethod(linkageCc); assert linkageCc.getArgumentCount() == args.length : "argument count mismatch"; Value[] argLocations = new Value[args.length]; for (int i = 0; i < args.length; i++) { @@ -775,7 +418,7 @@ emitMove(loc, arg); argLocations[i] = loc; } - this.hasForeignCall = true; + res.setForeignCall(true); emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state); if (isLegal(linkageCc.getReturn())) { @@ -785,46 +428,6 @@ } } - /** - * This method tries to create a switch implementation that is optimal for the given switch. It - * will either generate a sequential if/then/else cascade, a set of range tests or a table - * switch. - * - * If the given switch does not contain int keys, it will always create a sequential - * implementation. - */ - @Override - public void emitSwitch(SwitchNode x) { - assert x.defaultSuccessor() != null; - LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor()); - int keyCount = x.keyCount(); - if (keyCount == 0) { - emitJump(defaultTarget); - } else { - Variable value = load(operand(x.value())); - if (keyCount == 1) { - assert defaultTarget != null; - double probability = x.probability(x.keySuccessor(0)); - emitCompareBranch(load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability); - } else { - LabelRef[] keyTargets = new LabelRef[keyCount]; - Constant[] keyConstants = new Constant[keyCount]; - double[] keyProbabilities = new double[keyCount]; - for (int i = 0; i < keyCount; i++) { - keyTargets[i] = getLIRBlock(x.keySuccessor(i)); - keyConstants[i] = x.keyAt(i); - keyProbabilities[i] = x.keyProbability(i); - } - if (value.getKind() != Kind.Int || !x.isSorted()) { - // hopefully only a few entries - emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget); - } else { - emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value); - } - } - } - } - protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) { int keyCount = keyConstants.length; SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets); @@ -856,8 +459,13 @@ protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key); - public FrameMap frameMap() { - return frameMap; + public CallingConvention getCallingConvention() { + return cc; + } + + public DebugInfoBuilder getDebugInfoBuilder() { + assert debugInfoBuilder != null; + return debugInfoBuilder; } @Override @@ -883,13 +491,13 @@ outOfLoopDominator = outOfLoopDominator.getDominator(); } if (outOfLoopDominator != lc.block) { - lc.unpin(lir); + lc.unpin(res.getLIR()); lc.block = outOfLoopDominator; } } if (lc.index != -1) { - assert lir.lir(lc.block).get(lc.index) == lc.op; + assert res.getLIR().getLIRforBlock(lc.block).get(lc.index) == lc.op; iter.remove(); } } @@ -910,7 +518,7 @@ } int groupSize = groupEnd - groupBegin; - List ops = lir.lir(block); + List ops = res.getLIR().getLIRforBlock(block); int lastIndex = ops.size() - 1; assert ops.get(lastIndex) instanceof BlockEndOp; int insertionIndex = lastIndex; @@ -1009,4 +617,12 @@ public abstract void emitByteSwap(Variable result, Value operand); public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length); + + public AbstractBlock getCurrentBlock() { + return currentBlock; + } + + void setCurrentBlock(AbstractBlock block) { + currentBlock = block; + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,789 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.gen; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.api.meta.Value.*; +import static com.oracle.graal.lir.LIR.*; +import static com.oracle.graal.nodes.ConstantNode.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.compiler.gen.LIRGenerator.LoadConstant; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.JumpOp; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; + +/** + * This class traverses the HIR instructions and generates LIR instructions from them. + */ +public abstract class NodeLIRGenerator implements NodeLIRGeneratorTool { + + private final NodeMap nodeOperands; + private final DebugInfoBuilder debugInfoBuilder; + + private final int traceLevel; + private final boolean printIRWithLIR; + + protected final LIRGenerator gen; + + private ValueNode currentInstruction; + private ValueNode lastInstructionPrinted; // Debugging only + + protected LIRGenerationResult res; + + public NodeLIRGenerator(StructuredGraph graph, LIRGenerationResult res, LIRGenerator gen) { + this.res = res; + this.nodeOperands = graph.createNodeMap(); + this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands); + this.gen = gen; + this.traceLevel = LIRGenerator.Options.TraceLIRGeneratorLevel.getValue(); + this.printIRWithLIR = LIRGenerator.Options.PrintIRWithLIR.getValue(); + gen.setDebugInfoBuilder(debugInfoBuilder); + } + + @SuppressWarnings("hiding") + protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { + return new DebugInfoBuilder(nodeOperands); + } + + /** + * Returns the operand that has been previously initialized by + * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code + * generation error to ask for the operand of ValueNode that doesn't have one yet. + * + * @param node A node that produces a result value. + */ + @Override + public Value operand(ValueNode node) { + Value operand = getOperand(node); + assert operand != null : String.format("missing operand for %1s", node); + return operand; + } + + @Override + public boolean hasOperand(ValueNode node) { + return getOperand(node) != null; + } + + private Value getOperand(ValueNode node) { + if (nodeOperands == null) { + return null; + } + Value operand = nodeOperands.get(node); + if (operand == null) { + operand = getConstantOperand(node); + } + return operand; + } + + private Value getConstantOperand(ValueNode node) { + if (!ConstantNodeRecordsUsages) { + Constant value = node.asConstant(); + if (value != null) { + if (gen.canInlineConstant(value)) { + return setResult(node, value); + } else { + Variable loadedValue; + if (gen.constantLoads == null) { + gen.constantLoads = new HashMap<>(); + } + LoadConstant load = gen.constantLoads.get(value); + assert gen.getCurrentBlock() instanceof Block; + if (load == null) { + int index = res.getLIR().getLIRforBlock(gen.getCurrentBlock()).size(); + loadedValue = gen.emitMove(value); + LIRInstruction op = res.getLIR().getLIRforBlock(gen.getCurrentBlock()).get(index); + gen.constantLoads.put(value, new LoadConstant(loadedValue, (Block) gen.getCurrentBlock(), index, op)); + } else { + Block dominator = ControlFlowGraph.commonDominator(load.block, (Block) gen.getCurrentBlock()); + loadedValue = load.variable; + if (dominator != load.block) { + load.unpin(res.getLIR()); + } else { + assert load.block != gen.getCurrentBlock() || load.index < res.getLIR().getLIRforBlock(gen.getCurrentBlock()).size(); + } + load.block = dominator; + } + return loadedValue; + } + } + } else { + // Constant is loaded by ConstantNode.generate() + } + return null; + } + + public ValueNode valueForOperand(Value value) { + for (Entry entry : getNodeOperands().entries()) { + if (entry.getValue().equals(value)) { + return (ValueNode) entry.getKey(); + } + } + return null; + } + + @Override + public Value setResult(ValueNode x, Value operand) { + assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable()); + assert nodeOperands == null || nodeOperands.get(x) == null : "operand cannot be set twice"; + assert operand != null && isLegal(operand) : "operand must be legal"; + assert operand.getKind().getStackKind() == x.getKind() || x.getKind() == Kind.Illegal : operand.getKind().getStackKind() + " must match " + x.getKind(); + assert !(x instanceof VirtualObjectNode); + nodeOperands.set(x, operand); + return operand; + } + + public LabelRef getLIRBlock(FixedNode b) { + assert res.getLIR().getControlFlowGraph() instanceof ControlFlowGraph; + Block result = ((ControlFlowGraph) res.getLIR().getControlFlowGraph()).blockFor(b); + int suxIndex = gen.getCurrentBlock().getSuccessors().indexOf(result); + assert suxIndex != -1 : "Block not in successor list of current block"; + + assert gen.getCurrentBlock() instanceof Block; + return LabelRef.forSuccessor(res.getLIR(), (Block) gen.getCurrentBlock(), suxIndex); + } + + public final void append(LIRInstruction op) { + if (printIRWithLIR && !TTY.isSuppressed()) { + if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { + lastInstructionPrinted = currentInstruction; + InstructionPrinter ip = new InstructionPrinter(TTY.out()); + ip.printInstructionListing(currentInstruction); + } + } + gen.append(op); + } + + public final void doBlockStart(AbstractBlock block) { + if (printIRWithLIR) { + TTY.print(block.toString()); + } + + gen.setCurrentBlock(block); + + // set up the list of LIR instructions + assert res.getLIR().getLIRforBlock(block) == null : "LIR list already computed for this block"; + res.getLIR().setLIRforBlock(block, new ArrayList()); + + append(new LabelOp(new Label(block.getId()), block.isAligned())); + + if (traceLevel >= 1) { + TTY.println("BEGIN Generating LIR for block B" + block.getId()); + } + } + + public final void doBlockEnd(AbstractBlock block) { + + if (traceLevel >= 1) { + TTY.println("END Generating LIR for block B" + block.getId()); + } + + gen.setCurrentBlock(null); + + if (printIRWithLIR) { + TTY.println(); + } + } + + public void doBlock(Block block, StructuredGraph graph, BlockMap> blockMap) { + doBlockStart(block); + + if (block == res.getLIR().getControlFlowGraph().getStartBlock()) { + assert block.getPredecessorCount() == 0; + emitPrologue(graph); + } else { + assert block.getPredecessorCount() > 0; + } + + List nodes = blockMap.get(block); + int instructionsFolded = 0; + for (int i = 0; i < nodes.size(); i++) { + Node instr = nodes.get(i); + if (traceLevel >= 3) { + TTY.println("LIRGen for " + instr); + } + if (instructionsFolded > 0) { + instructionsFolded--; + continue; + } + if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) { + // Loading of constants is done lazily by operand() + + } else if (instr instanceof ValueNode) { + ValueNode valueNode = (ValueNode) instr; + if (!hasOperand(valueNode)) { + if (!peephole(valueNode)) { + instructionsFolded = maybeFoldMemory(nodes, i, valueNode); + if (instructionsFolded == 0) { + try { + doRoot((ValueNode) instr); + } catch (GraalInternalError e) { + throw e.addContext(instr); + } catch (Throwable e) { + throw new GraalInternalError(e).addContext(instr); + } + } + } + } else { + // There can be cases in which the result of an instruction is already set + // before by other instructions. + } + } + } + + if (!hasBlockEnd(block)) { + NodeClassIterable successors = block.getEndNode().successors(); + assert successors.count() == block.getSuccessorCount(); + if (block.getSuccessorCount() != 1) { + /* + * If we have more than one successor, we cannot just use the first one. Since + * successors are unordered, this would be a random choice. + */ + throw new GraalInternalError("Block without BlockEndOp: " + block.getEndNode()); + } + gen.emitJump(getLIRBlock((FixedNode) successors.first())); + } + + assert verifyBlock(res.getLIR(), block); + doBlockEnd(block); + } + + private static final DebugMetric MemoryFoldSuccess = Debug.metric("MemoryFoldSuccess"); + private static final DebugMetric MemoryFoldFailed = Debug.metric("MemoryFoldFailed"); + private static final DebugMetric MemoryFoldFailedNonAdjacent = Debug.metric("MemoryFoldedFailedNonAdjacent"); + private static final DebugMetric MemoryFoldFailedDifferentBlock = Debug.metric("MemoryFoldedFailedDifferentBlock"); + + /** + * Subclass can provide helper to fold memory operations into other operations. + */ + public MemoryArithmeticLIRLowerer getMemoryLowerer() { + return null; + } + + private static final Object LOG_OUTPUT_LOCK = new Object(); + + /** + * Try to find a sequence of Nodes which can be passed to the backend to look for optimized + * instruction sequences using memory. Currently this basically is a read with a single + * arithmetic user followed by an possible if use. This should generalized to more generic + * pattern matching so that it can be more flexibly used. + */ + private int maybeFoldMemory(List nodes, int i, ValueNode access) { + MemoryArithmeticLIRLowerer lowerer = getMemoryLowerer(); + if (lowerer != null && GraalOptions.OptFoldMemory.getValue() && (access instanceof ReadNode || access instanceof FloatingReadNode) && access.usages().count() == 1 && i + 1 < nodes.size()) { + try (Scope s = Debug.scope("MaybeFoldMemory", access)) { + // This is all bit hacky since it's happening on the linearized schedule. This needs + // to be revisited at some point. + + // Find a memory lowerable usage of this operation + if (access.usages().first() instanceof MemoryArithmeticLIRLowerable) { + ValueNode operation = (ValueNode) access.usages().first(); + if (!nodes.contains(operation)) { + Debug.log("node %1s in different block from %1s", access, operation); + MemoryFoldFailedDifferentBlock.increment(); + return 0; + } + ValueNode firstOperation = operation; + if (operation instanceof LogicNode) { + if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) { + ValueNode ifNode = (ValueNode) operation.usages().first(); + if (!nodes.contains(ifNode)) { + MemoryFoldFailedDifferentBlock.increment(); + Debug.log("if node %1s in different block from %1s", ifNode, operation); + try (Indent indent = Debug.logAndIndent("checking operations")) { + int start = nodes.indexOf(access); + int end = nodes.indexOf(operation); + for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) { + Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); + } + } + return 0; + } else { + operation = ifNode; + } + } + } + if (Debug.isLogEnabled()) { + synchronized (LOG_OUTPUT_LOCK) { // Hack to ensure the output is grouped. + try (Indent indent = Debug.logAndIndent("checking operations")) { + int start = nodes.indexOf(access); + int end = nodes.indexOf(operation); + for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) { + Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); + } + } + } + } + // Possible lowerable operation in the same block. Check out the dependencies. + int opIndex = nodes.indexOf(operation); + int current = i + 1; + ArrayList deferred = null; + while (current < opIndex) { + ScheduledNode node = nodes.get(current); + if (node != firstOperation) { + if (node instanceof LocationNode || node instanceof VirtualObjectNode) { + // nothing to do + } else if (node instanceof ConstantNode) { + if (deferred == null) { + deferred = new ArrayList<>(2); + } + // These nodes are collected and the backend is expended to + // evaluate them before generating the lowered form. This + // basically works around unfriendly scheduling of values which + // are defined in a block but not used there. + deferred.add((ValueNode) node); + } else { + Debug.log("unexpected node %1s", node); + // Unexpected inline node + break; + } + } + current++; + } + + if (current == opIndex) { + if (lowerer.memoryPeephole((Access) access, (MemoryArithmeticLIRLowerable) operation, deferred)) { + MemoryFoldSuccess.increment(); + // if this operation had multiple access inputs, then previous attempts + // would be marked as failures which is wrong. Try to adjust the + // counters to account for this. + for (Node input : operation.inputs()) { + if (input == access) { + continue; + } + if (input instanceof Access && nodes.contains(input)) { + MemoryFoldFailedNonAdjacent.add(-1); + } + } + if (deferred != null) { + // Ensure deferred nodes were evaluated + for (ValueNode node : deferred) { + assert hasOperand(node); + } + } + return opIndex - i; + } else { + // This isn't true failure, it just means there wasn't match for the + // pattern. Usually that means it's just not supported by the backend. + MemoryFoldFailed.increment(); + return 0; + } + } else { + MemoryFoldFailedNonAdjacent.increment(); + } + } else { + // memory usage which isn't considered lowerable. Mostly these are + // uninteresting but it might be worth looking at to ensure that interesting + // nodes are being properly handled. + // Debug.log("usage isn't lowerable %1s", access.usages().first()); + } + } + } + return 0; + } + + protected abstract boolean peephole(ValueNode valueNode); + + private boolean hasBlockEnd(Block block) { + List ops = res.getLIR().getLIRforBlock(block); + if (ops.size() == 0) { + return false; + } + return ops.get(ops.size() - 1) instanceof BlockEndOp; + } + + private void doRoot(ValueNode instr) { + if (traceLevel >= 2) { + TTY.println("Emitting LIR for instruction " + instr); + } + currentInstruction = instr; + + Debug.log("Visiting %s", instr); + emitNode(instr); + Debug.log("Operand for %s = %s", instr, getOperand(instr)); + } + + protected void emitNode(ValueNode node) { + if (Debug.isLogEnabled() && node.stamp() instanceof IllegalStamp) { + Debug.log("This node has invalid type, we are emitting dead code(?): %s", node); + } + if (node instanceof LIRGenLowerable) { + ((LIRGenLowerable) node).generate(this); + } else if (node instanceof LIRGenResLowerable) { + ((LIRGenResLowerable) node).generate(this, res); + } else if (node instanceof LIRLowerable) { + ((LIRLowerable) node).generate(this); + } else if (node instanceof ArithmeticLIRLowerable) { + ((ArithmeticLIRLowerable) node).generate(this); + } else { + throw GraalInternalError.shouldNotReachHere("node is not LIRLowerable: " + node); + } + } + + protected void emitPrologue(StructuredGraph graph) { + CallingConvention incomingArguments = gen.getCallingConvention(); + + Value[] params = new Value[incomingArguments.getArgumentCount()]; + for (int i = 0; i < params.length; i++) { + params[i] = toStackKind(incomingArguments.getArgument(i)); + if (ValueUtil.isStackSlot(params[i])) { + StackSlot slot = ValueUtil.asStackSlot(params[i]); + if (slot.isInCallerFrame() && !res.getLIR().hasArgInCallerFrame()) { + res.getLIR().setHasArgInCallerFrame(); + } + } + } + + emitIncomingValues(params); + + for (ParameterNode param : graph.getNodes(ParameterNode.class)) { + Value paramValue = params[param.index()]; + assert paramValue.getKind() == param.getKind().getStackKind(); + setResult(param, gen.emitMove(paramValue)); + } + } + + protected > void emitPrologue(ResolvedJavaMethod method, BytecodeParser parser) { + CallingConvention incomingArguments = gen.getCallingConvention(); + + Value[] params = new Value[incomingArguments.getArgumentCount()]; + for (int i = 0; i < params.length; i++) { + params[i] = toStackKind(incomingArguments.getArgument(i)); + if (ValueUtil.isStackSlot(params[i])) { + StackSlot slot = ValueUtil.asStackSlot(params[i]); + if (slot.isInCallerFrame() && !res.getLIR().hasArgInCallerFrame()) { + res.getLIR().setHasArgInCallerFrame(); + } + } + } + + emitIncomingValues(params); + + Signature sig = method.getSignature(); + boolean isStatic = Modifier.isStatic(method.getModifiers()); + for (int i = 0; i < sig.getParameterCount(!isStatic); i++) { + Value paramValue = params[i]; + assert paramValue.getKind() == sig.getParameterKind(i).getStackKind(); + // TODO setResult(param, emitMove(paramValue)); + parser.setParameter(i, gen.emitMove(paramValue)); + } + + // return arguments; + } + + public void emitIncomingValues(Value[] params) { + ((LabelOp) res.getLIR().getLIRforBlock(gen.getCurrentBlock()).get(0)).setIncomingValues(params); + } + + @Override + public void visitReturn(ReturnNode x) { + AllocatableValue operand = ILLEGAL; + if (x.result() != null) { + operand = gen.resultOperandFor(x.result().getKind()); + gen.emitMove(operand, operand(x.result())); + } + gen.emitReturn(operand); + } + + @Override + public void visitMerge(MergeNode x) { + } + + @Override + public void visitEndNode(AbstractEndNode end) { + moveToPhi(end.merge(), end); + } + + /** + * Runtime specific classes can override this to insert a safepoint at the end of a loop. + */ + @Override + public void visitLoopEnd(LoopEndNode x) { + } + + private void moveToPhi(MergeNode merge, AbstractEndNode pred) { + if (traceLevel >= 1) { + TTY.println("MOVE TO PHI from " + pred + " to " + merge); + } + PhiResolver resolver = new PhiResolver(gen); + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value) { + ValueNode curVal = phi.valueAt(pred); + resolver.move(operandForPhi(phi), operand(curVal)); + } + } + resolver.dispose(); + + append(new JumpOp(getLIRBlock(merge))); + } + + protected PlatformKind getPhiKind(PhiNode phi) { + return phi.getKind(); + } + + private Value operandForPhi(PhiNode phi) { + assert phi.type() == PhiType.Value : "wrong phi type: " + phi; + Value result = getOperand(phi); + if (result == null) { + // allocate a variable for this phi + Variable newOperand = gen.newVariable(getPhiKind(phi)); + setResult(phi, newOperand); + return newOperand; + } else { + return result; + } + } + + @Override + public void emitIf(IfNode x) { + emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); + } + + public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + if (node instanceof IsNullNode) { + emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else if (node instanceof CompareNode) { + emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else if (node instanceof LogicConstantNode) { + emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor); + } else if (node instanceof IntegerTestNode) { + emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } else { + throw GraalInternalError.unimplemented(node.toString()); + } + } + + private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + gen.emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + gen.emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + gen.emitIntegerTestBranch(operand(test.x()), operand(test.y()), trueSuccessor, falseSuccessor, trueSuccessorProbability); + } + + public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { + LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock; + gen.emitJump(block); + } + + @Override + public void emitConditional(ConditionalNode conditional) { + Value tVal = operand(conditional.trueValue()); + Value fVal = operand(conditional.falseValue()); + setResult(conditional, emitConditional(conditional.condition(), tVal, fVal)); + } + + public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) { + if (node instanceof IsNullNode) { + IsNullNode isNullNode = (IsNullNode) node; + return gen.emitConditionalMove(operand(isNullNode.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueValue, falseValue); + } else if (node instanceof CompareNode) { + CompareNode compare = (CompareNode) node; + return gen.emitConditionalMove(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue); + } else if (node instanceof LogicConstantNode) { + return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue); + } else if (node instanceof IntegerTestNode) { + IntegerTestNode test = (IntegerTestNode) node; + return gen.emitIntegerTestMove(operand(test.x()), operand(test.y()), trueValue, falseValue); + } else { + throw GraalInternalError.unimplemented(node.toString()); + } + } + + @Override + public void emitInvoke(Invoke x) { + LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget(); + CallingConvention invokeCc = res.getFrameMap().registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()), callTarget.signature(), + gen.target(), false); + res.getFrameMap().callsMethod(invokeCc); + + Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments()); + + LabelRef exceptionEdge = null; + if (x instanceof InvokeWithExceptionNode) { + exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()); + } + LIRFrameState callState = gen.stateWithExceptionEdge(x, exceptionEdge); + + Value result = invokeCc.getReturn(); + if (callTarget instanceof DirectCallTargetNode) { + emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); + } else if (callTarget instanceof IndirectCallTargetNode) { + emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + + if (isLegal(result)) { + setResult(x.asNode(), gen.emitMove(result)); + } + + if (x instanceof InvokeWithExceptionNode) { + gen.emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next())); + } + } + + protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); + + protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); + + protected static AllocatableValue toStackKind(AllocatableValue value) { + if (value.getKind().getStackKind() != value.getKind()) { + // We only have stack-kinds in the LIR, so convert the operand kind for values from the + // calling convention. + if (isRegister(value)) { + return asRegister(value).asValue(value.getKind().getStackKind()); + } else if (isStackSlot(value)) { + return StackSlot.get(value.getKind().getStackKind(), asStackSlot(value).getRawOffset(), asStackSlot(value).getRawAddFrameSize()); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } + return value; + } + + @Override + public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection arguments) { + // for each argument, load it into the correct location + Value[] result = new Value[arguments.size()]; + int j = 0; + for (ValueNode arg : arguments) { + if (arg != null) { + AllocatableValue operand = toStackKind(invokeCc.getArgument(j)); + gen.emitMove(operand, operand(arg)); + result[j] = operand; + j++; + } else { + throw GraalInternalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types..."); + } + } + return result; + } + + /** + * This method tries to create a switch implementation that is optimal for the given switch. It + * will either generate a sequential if/then/else cascade, a set of range tests or a table + * switch. + * + * If the given switch does not contain int keys, it will always create a sequential + * implementation. + */ + @Override + public void emitSwitch(SwitchNode x) { + assert x.defaultSuccessor() != null; + LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor()); + int keyCount = x.keyCount(); + if (keyCount == 0) { + gen.emitJump(defaultTarget); + } else { + Variable value = gen.load(operand(x.value())); + if (keyCount == 1) { + assert defaultTarget != null; + double probability = x.probability(x.keySuccessor(0)); + gen.emitCompareBranch(gen.load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability); + } else { + LabelRef[] keyTargets = new LabelRef[keyCount]; + Constant[] keyConstants = new Constant[keyCount]; + double[] keyProbabilities = new double[keyCount]; + for (int i = 0; i < keyCount; i++) { + keyTargets[i] = getLIRBlock(x.keySuccessor(i)); + keyConstants[i] = x.keyAt(i); + keyProbabilities[i] = x.keyProbability(i); + } + if (value.getKind() != Kind.Int || !x.isSorted()) { + // hopefully only a few entries + gen.emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget); + } else { + gen.emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value); + } + } + } + } + + public final NodeMap getNodeOperands() { + assert nodeOperands != null; + return nodeOperands; + } + + public DebugInfoBuilder getDebugInfoBuilder() { + assert debugInfoBuilder != null; + return debugInfoBuilder; + } + + public void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, double probability) { + gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), probability); + } + + public final void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { + gen.emitArrayEquals(kind, result, array1, array2, length); + } + + public final Variable newVariable(Kind i) { + return gen.newVariable(i); + } + + public final void emitBitCount(Variable result, Value operand) { + gen.emitBitCount(result, operand); + } + + public final void emitBitScanForward(Variable result, Value operand) { + gen.emitBitScanForward(result, operand); + } + + final void emitBitScanReverse(Variable result, Value operand) { + gen.emitBitScanReverse(result, operand); + } + + @Override + public LIRGenerator getLIRGeneratorTool() { + return gen; + } + + public LIRGenerator getLIRGenerator() { + return gen; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Sun Mar 30 16:08:33 2014 +0200 @@ -25,15 +25,29 @@ import static com.oracle.graal.phases.GraalOptions.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; public class LowTier extends PhaseSuite { + static class Options { + + // @formatter:off + @Option(help = "") + public static final OptionValue ProfileCompiledMethods = new OptionValue<>(false); + // @formatter:on + + } + public LowTier() { CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue()); + if (Options.ProfileCompiledMethods.getValue()) { + appendPhase(new ProfileCompiledMethodsPhase()); + } + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER)); appendPhase(new RemoveValueProxyPhase()); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Sun Mar 30 16:08:33 2014 +0200 @@ -65,7 +65,11 @@ public abstract FrameMap newFrameMap(); - public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir); + public abstract LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes); + + public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub); + + public abstract NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen); /** * Creates the assembler used to emit the machine code. @@ -75,7 +79,7 @@ /** * Creates the object used to fill in the details of a given compilation result. */ - public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory); + public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, CompilationResult compilationResult, CompilationResultBuilderFactory factory); public abstract boolean shouldAllocateRegisters(); @@ -87,4 +91,5 @@ * argument can be null. */ public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner); + } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java Sun Mar 30 16:08:33 2014 +0200 @@ -32,5 +32,5 @@ */ public interface LIRGenLowerable { - void generate(LIRGenerator generator); + void generate(NodeLIRGenerator generator); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenResLowerable.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.target; + +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.spi.*; + +/** + * An alternative to {@link LIRLowerable} for lowering that is tightly coupled to + * {@link LIRGenerationResult} and {@link LIRInstruction}. + */ +public interface LIRGenResLowerable { + + void generate(NodeLIRGeneratorTool generator, LIRGenerationResult genRes); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.debug; import static com.oracle.graal.debug.Debug.Initialization.*; +import static java.util.FormattableFlags.*; import java.io.*; import java.util.*; @@ -129,7 +130,7 @@ /** * Gets a string composed of the names in the current nesting of debug - * {@linkplain #scope(String, Object...) scopes} separated by {@code '.'}. + * {@linkplain #scope(Object) scopes} separated by {@code '.'}. */ public static String currentScope() { if (ENABLED) { @@ -140,7 +141,7 @@ } /** - * Represents a debug scope entered by {@link Debug#scope(String, Object...)} or + * Represents a debug scope entered by {@link Debug#scope(Object)} or * {@link Debug#sandbox(String, DebugConfig, Object...)}. Leaving the scope is achieved via * {@link #close()}. */ @@ -153,7 +154,7 @@ *

* It is recommended to use the try-with-resource statement for managing entering and leaving * debug scopes. For example: - * + * *

      * try (Scope s = Debug.scope("InliningGraph", inlineeGraph)) {
      *     ...
@@ -161,15 +162,68 @@
      *     throw Debug.handle(e);
      * }
      * 
- * + * + * The {@code name} argument is subject to the following type based conversion before having + * {@link Object#toString()} called on it: + * + *
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * 
+ * * @param name the name of the new scope - * @param context objects to be appended to the {@linkplain #context() current} debug context * @return the scope entered by this method which will be exited when its {@link Scope#close()} * method is called */ - public static Scope scope(CharSequence name, Object... context) { + public static Scope scope(Object name) { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null); + } else { + return null; + } + } + + /** + * @see #scope(Object) + * @param context an object to be appended to the {@linkplain #context() current} debug context + */ + public static Scope scope(Object name, Object context) { if (ENABLED) { - return DebugScope.getInstance().scope(name, null, context); + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context); + } else { + return null; + } + } + + /** + * @see #scope(Object) + * @param context1 first object to be appended to the {@linkplain #context() current} debug + * context + * @param context2 second object to be appended to the {@linkplain #context() current} debug + * context + */ + public static Scope scope(Object name, Object context1, Object context2) { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2); + } else { + return null; + } + } + + /** + * @see #scope(Object) + * @param context1 first object to be appended to the {@linkplain #context() current} debug + * context + * @param context2 second object to be appended to the {@linkplain #context() current} debug + * context + * @param context3 third object to be appended to the {@linkplain #context() current} debug + * context + */ + public static Scope scope(Object name, Object context1, Object context2, Object context3) { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2, context3); } else { return null; } @@ -180,7 +234,7 @@ *

* It is recommended to use the try-with-resource statement for managing entering and leaving * debug scopes. For example: - * + * *

      * try (Scope s = Debug.sandbox("CompilingStub", null, stubGraph)) {
      *     ...
@@ -188,7 +242,7 @@
      *     throw Debug.handle(e);
      * }
      * 
- * + * * @param name the name of the new scope * @param config the debug configuration to use for the new scope * @param context objects to be appended to the {@linkplain #context() current} debug context @@ -221,10 +275,10 @@ /** * Handles an exception in the context of the debug scope just exited. The just exited scope * must have the current scope as its parent which will be the case if the try-with-resource - * pattern recommended by {@link #scope(String, Object...)} and + * pattern recommended by {@link #scope(Object)} and * {@link #sandbox(String, DebugConfig, Object...)} is used - * - * @see #scope(String, Object...) + * + * @see #scope(Object) * @see #sandbox(String, DebugConfig, Object...) */ public static RuntimeException handle(Throwable exception) { @@ -242,92 +296,232 @@ } /** - * Prints an indented message to the current debug scopes's logging stream if logging is enabled - * in the scope. - * - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @see Indent#log + * Prints a message to the current debug scope's logging stream if logging is enabled. + * + * @param msg the message to log + */ + public static void log(String msg) { + if (ENABLED) { + DebugScope.getInstance().log(msg); + } + } + + /** + * Prints a message to the current debug scope's logging stream if logging is enabled. + * + * @param format a format string + * @param arg the argument referenced by the format specifiers in {@code format} + */ + public static void log(String format, Object arg) { + if (ENABLED) { + DebugScope.getInstance().log(format, arg); + } + } + + /** + * @see #log(String, Object) */ - public static void log(String msg, Object... args) { + public static void log(String format, Object arg1, Object arg2) { + if (ENABLED) { + DebugScope.getInstance().log(format, arg1, arg2); + } + } + + /** + * @see #log(String, Object) + */ + public static void log(String format, Object arg1, Object arg2, Object arg3) { + if (ENABLED) { + DebugScope.getInstance().log(format, arg1, arg2, arg3); + } + } + + /** + * @see #log(String, Object) + */ + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) { if (ENABLED) { - DebugScope.getInstance().log(msg, args); + DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4); + } + } + + /** + * @see #log(String, Object) + */ + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { + if (ENABLED) { + DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4, arg5); + } + } + + /** + * @see #log(String, Object) + */ + public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { + if (ENABLED) { + DebugScope.getInstance().log(format, arg1, arg2, arg3, arg4, arg5, arg6); } } /** - * The same as {@link #log}, but without line termination and without indentation. + * Prints a message to the current debug scope's logging stream. This method must only be called + * if debugging is {@linkplain Debug#isEnabled() enabled} as it incurs allocation at the call + * site. If possible, call one of the other {@code log()} methods in this class that take a + * fixed number of parameters. + * + * @param format a format string + * @param args the arguments referenced by the format specifiers in {@code format} */ - public static void printf(String msg, Object... args) { - if (ENABLED && DebugScope.getInstance().isLogEnabled()) { - DebugScope.getInstance().printf(msg, args); + public static void logv(String format, Object... args) { + if (!ENABLED) { + throw new InternalError("Use of Debug.logv() must be guarded by a test of Debug.isEnabled()"); } + DebugScope.getInstance().log(format, args); } - public static void dump(Object object, String msg, Object... args) { + /** + * This override exists to catch cases when {@link #log(String, Object)} is called with one + * argument bound to a varargs method parameter. It will bind to this method instead of the + * single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void log(String format, Object[] args) { + assert false : "shouldn't use this"; + logv(format, args); + } + + public static void dump(Object object, String msg) { if (ENABLED && DebugScope.getInstance().isDumpEnabled()) { - DebugScope.getInstance().dump(object, msg, args); + DebugScope.getInstance().dump(object, msg); } } - private static final class NoLogger implements Indent { - - @Override - public void log(String msg, Object... args) { + public static void dump(Object object, String format, Object arg) { + if (ENABLED && DebugScope.getInstance().isDumpEnabled()) { + DebugScope.getInstance().dump(object, format, arg); } - - @Override - public Indent indent() { - return this; - } + } - @Override - public Indent logAndIndent(String msg, Object... args) { - return this; + public static void dump(Object object, String format, Object arg1, Object arg2) { + if (ENABLED && DebugScope.getInstance().isDumpEnabled()) { + DebugScope.getInstance().dump(object, format, arg1, arg2); } + } - @Override - public Indent outdent() { - return this; - } - - @Override - public void close() { + public static void dump(Object object, String format, Object arg1, Object arg2, Object arg3) { + if (ENABLED && DebugScope.getInstance().isDumpEnabled()) { + DebugScope.getInstance().dump(object, format, arg1, arg2, arg3); } } - private static final NoLogger noLoggerInstance = new NoLogger(); + /** + * This override exists to catch cases when {@link #dump(Object, String, Object)} is called with + * one argument bound to a varargs method parameter. It will bind to this method instead of the + * single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void dump(Object object, String format, Object[] args) { + assert false : "shouldn't use this"; + if (ENABLED && DebugScope.getInstance().isDumpEnabled()) { + DebugScope.getInstance().dump(object, format, args); + } + } /** - * Creates a new indentation level (by adding some spaces) based on the last used Indent of the - * current DebugScope. - * - * @return The new indentation level - * @see Indent#indent + * Opens a new indentation level (by adding some spaces) based on the current indentation level. + * This should be used in a {@linkplain Indent try-with-resources} pattern. + * + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + * @see #logAndIndent(String) + * @see #logAndIndent(String, Object) */ public static Indent indent() { if (ENABLED) { DebugScope scope = DebugScope.getInstance(); return scope.pushIndentLogger(); } - return noLoggerInstance; + return null; + } + + /** + * A convenience function which combines {@link #log(String)} and {@link #indent()}. + * + * @param msg the message to log + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logAndIndent(String msg) { + if (ENABLED) { + return logvAndIndent(msg); + } + return null; + } + + /** + * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}. + * + * @param format a format string + * @param arg the argument referenced by the format specifiers in {@code format} + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logAndIndent(String format, Object arg) { + if (ENABLED) { + return logvAndIndent(format, arg); + } + return null; } /** - * A convenience function which combines {@link #log} and {@link #indent()}. - * - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @return The new indentation level - * @see Indent#logAndIndent + * @see #logAndIndent(String, Object) + */ + public static Indent logAndIndent(String format, Object arg1, Object arg2) { + if (ENABLED) { + return logvAndIndent(format, arg1, arg2); + } + return null; + } + + /** + * @see #logAndIndent(String, Object) */ - public static Indent logAndIndent(String msg, Object... args) { + public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) { + if (ENABLED) { + return logvAndIndent(format, arg1, arg2, arg3); + } + return null; + } + + /** + * A convenience function which combines {@link #logv(String, Object...)} and {@link #indent()}. + * + * @param format a format string + * @param args the arguments referenced by the format specifiers in {@code format} + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logvAndIndent(String format, Object... args) { if (ENABLED) { DebugScope scope = DebugScope.getInstance(); - scope.log(msg, args); + scope.log(format, args); return scope.pushIndentLogger(); } - return noLoggerInstance; + throw new InternalError("Use of Debug.logvAndIndent() must be guarded by a test of Debug.isEnabled()"); + } + + /** + * This override exists to catch cases when {@link #logAndIndent(String, Object)} is called with + * one argument bound to a varargs method parameter. It will bind to this method instead of the + * single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void logAndIndent(String format, Object[] args) { + assert false : "shouldn't use this"; + logvAndIndent(format, args); } public static Iterable context() { @@ -380,18 +574,91 @@ * A disabled metric has virtually no overhead. */ public static DebugMetric metric(CharSequence name) { - if (enabledMetrics != null && enabledMetrics.contains(name.toString())) { - return new MetricImpl(name.toString(), false); - } else if (ENABLED) { - return new MetricImpl(name.toString(), true); - } else { + if (enabledMetrics == null && !ENABLED) { return VOID_METRIC; } + return createMetric("%s", name, null); + } + + public static String applyFormattingFlagsAndWidth(String s, int flags, int width) { + if (flags == 0 && width < 0) { + return s; + } + StringBuilder sb = new StringBuilder(s); + + // apply width and justification + int len = sb.length(); + if (len < width) { + for (int i = 0; i < width - len; i++) { + if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) { + sb.append(' '); + } else { + sb.insert(0, ' '); + } + } + } + + String res = sb.toString(); + if ((flags & UPPERCASE) == UPPERCASE) { + res = res.toUpperCase(); + } + return res; + } + + /** + * Creates a debug metric. Invoking this method is equivalent to: + * + *
+     * Debug.metric(format, arg, null)
+     * 
+ * + * except that the string formatting only happens if metering is enabled. + * + * @see #metric(String, Object, Object) + */ + public static DebugMetric metric(String format, Object arg) { + if (enabledMetrics == null && !ENABLED) { + return VOID_METRIC; + } + return createMetric(format, arg, null); + } + + /** + * Creates a debug metric. Invoking this method is equivalent to: + * + *
+     * Debug.metric(String.format(format, arg1, arg2))
+     * 
+ * + * except that the string formatting only happens if metering is enabled. In addition, each + * argument is subject to the following type based conversion before being passed as an argument + * to {@link String#format(String, Object...)}: + * + *
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * 
+ * + * @see #metric(CharSequence) + */ + public static DebugMetric metric(String format, Object arg1, Object arg2) { + if (enabledMetrics == null && !ENABLED) { + return VOID_METRIC; + } + return createMetric(format, arg1, arg2); + } + + private static DebugMetric createMetric(String format, Object arg1, Object arg2) { + String name = formatDebugName(format, arg1, arg2); + boolean conditional = enabledMetrics != null && enabledMetrics.contains(name); + return new MetricImpl(name, conditional); } /** * Changes the debug configuration for the current thread. - * + * * @param config new configuration to use for the current thread * @return an object that when {@linkplain DebugConfigScope#close() closed} will restore the * debug configuration for the current thread to what it was before this method was @@ -533,13 +800,72 @@ * A disabled timer has virtually no overhead. */ public static DebugTimer timer(CharSequence name) { - if (enabledTimers != null && enabledTimers.contains(name.toString())) { - return new TimerImpl(name.toString(), false); - } else if (ENABLED) { - return new TimerImpl(name.toString(), true); - } else { + if (enabledTimers == null && !ENABLED) { + return VOID_TIMER; + } + return createTimer("%s", name, null); + } + + /** + * Creates a debug timer. Invoking this method is equivalent to: + * + *
+     * Debug.timer(format, arg, null)
+     * 
+ * + * except that the string formatting only happens if timing is enabled. + * + * @see #timer(String, Object, Object) + */ + public static DebugTimer timer(String format, Object arg) { + if (enabledTimers == null && !ENABLED) { return VOID_TIMER; } + return createTimer(format, arg, null); + } + + /** + * Creates a debug timer. Invoking this method is equivalent to: + * + *
+     * Debug.timer(String.format(format, arg1, arg2))
+     * 
+ * + * except that the string formatting only happens if timing is enabled. In addition, each + * argument is subject to the following type based conversion before being passed as an argument + * to {@link String#format(String, Object...)}: + * + *
+     *     Type          | Conversion
+     * ------------------+-----------------
+     *  java.lang.Class  | arg.getSimpleName()
+     *                   |
+     * 
+ * + * @see #timer(CharSequence) + */ + public static DebugTimer timer(String format, Object arg1, Object arg2) { + if (enabledTimers == null && !ENABLED) { + return VOID_TIMER; + } + return createTimer(format, arg1, arg2); + } + + public static Object convertFormatArg(Object arg) { + if (arg instanceof Class) { + return ((Class) arg).getSimpleName(); + } + return arg; + } + + private static String formatDebugName(String format, Object arg1, Object arg2) { + return String.format(format, convertFormatArg(arg1), convertFormatArg(arg2)); + } + + private static DebugTimer createTimer(String format, Object arg1, Object arg2) { + String name = formatDebugName(format, arg1, arg2); + boolean conditional = enabledTimers != null && enabledTimers.contains(name); + return new TimerImpl(name, conditional); } private static final DebugTimer VOID_TIMER = new DebugTimer() { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfig.java Sun Mar 30 16:08:33 2014 +0200 @@ -28,10 +28,7 @@ public interface DebugConfig { /** - * Determines if logging is enabled in the {@linkplain Debug#currentScope() current debug scope} - * . - * - * @see Debug#log(String, Object...) + * Determines if logging is on in the {@linkplain Debug#currentScope() current debug scope} . */ boolean isLogEnabled(); @@ -44,7 +41,7 @@ /** * Determines if metering is enabled in the {@linkplain Debug#currentScope() current debug * scope}. - * + * * @see Debug#metric(CharSequence) */ boolean isMeterEnabled(); @@ -52,8 +49,8 @@ /** * Determines if dumping is enabled in the {@linkplain Debug#currentScope() current debug scope} * . - * - * @see Debug#dump(Object, String, Object...) + * + * @see Debug#dump(Object, String) */ boolean isDumpEnabled(); @@ -70,7 +67,7 @@ /** * Removes an object the context used by this configuration to do filtering. - * + * * This should only removes extra context added by {@link #addToContext(Object)}. */ void removeFromContext(Object o); @@ -82,7 +79,7 @@ /** * Handles notification of an exception occurring within a debug scope. - * + * * @return the exception object that is to be propagated to parent scope. A value of * {@code null} indicates that {@code e} is to be propagated. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,80 +23,29 @@ package com.oracle.graal.debug; /** - * Represents an indentation level for logging. - *

- * Note that calling the logging/indent/outdent methods of this interface updates the last used - * Indent of the current DebugScope. If no instance of Indent is available (e.g. at the beginning of - * a method), then the corresponding static methods of the Debug class should be used. They perform - * logging and indentation based on the last used Indent of the current DebugScope. + * Object used to close a debug {@link Debug#indent() indentation} scope. *

* Example usage: - * + * *

- *      void method() {
- *      
- *          Indent in = Debug.logIndent("header message");
+ *
+ *      try (Indent i1 = Debug.logAndIndent("header message")) {
  *          ...
- *          in.log("message");
- *          ...
- *          Indent in2 = in.logIndent("sub-header message");
- *          ...
- *          {
- *              in2.log("inner message");
- *          }
+ *          Debug.log("message");
  *          ...
- *          in.outdent();
+ *          try (Indent i2 = Debug.logAndIndent(sub-header message")) {
+ *              ...
+ *              Debug.log("inner message");
+ *              ...
+ *          }
  *      }
- * 
- * - * Example usage with try-with-resources: - * - *
- * 
- *      try (Indent in = Debug.logIndent("header message")) {
- *          ...
- *          in.log("message");
- *          ...
- *      }
- * 
+ *
  * 
*/ public interface Indent extends AutoCloseable { /** - * Prints an indented message to the DebugLevel's logging stream if logging is enabled. - * - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @see Debug#log - */ - void log(String msg, Object... args); - - /** - * Creates a new indentation level (by adding some spaces). - * - * @return The new indentation level - * @see Debug#indent + * Closes the current indentation scope. */ - Indent indent(); - - /** - * A convenience function which combines {@link #log} and {@link #indent}. - * - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @return The new indentation level - * @see Debug#logAndIndent - */ - Indent logAndIndent(String msg, Object... args); - - /** - * Restores the previous indent level. Calling this method is important to restore the correct - * last used Indent in the current DebugScope. - * - * @return The indent level from which this Indent was created. - */ - Indent outdent(); - void close(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Sun Mar 30 16:08:33 2014 +0200 @@ -52,7 +52,6 @@ } } - @Override public void log(String msg, Object... args) { if (isLogEnabled()) { printScopeName(); @@ -61,29 +60,16 @@ } } - @Override - public Indent indent() { + IndentImpl indent() { lastUsedIndent = new IndentImpl(this); return lastUsedIndent; } @Override - public Indent logAndIndent(String msg, Object... args) { - log(msg, args); - return indent(); - } - - @Override - public Indent outdent() { + public void close() { if (parentIndent != null) { lastUsedIndent = parentIndent; } - return lastUsedIndent; - } - - @Override - public void close() { - outdent(); } } @@ -194,7 +180,7 @@ } } - public void dump(Object object, String formatString, Object[] args) { + public void dump(Object object, String formatString, Object... args) { if (isDumpEnabled()) { DebugConfig config = getConfig(); if (config != null) { @@ -209,7 +195,7 @@ /** * This method exists mainly to allow a debugger (e.g., Eclipse) to force dump a graph. */ - public static void dump(Object object, String message) { + public static void forceDump(Object object, String message) { DebugConfig config = getConfig(); if (config != null) { for (DebugDumpHandler dumpHandler : config.dumpHandlers()) { @@ -224,7 +210,7 @@ /** * Creates and enters a new debug scope which is either a child of the current scope or a * disjoint top level scope. - * + * * @param name the name of the new scope * @param sandboxConfig the configuration to use for a new top level scope, or null if the new * scope should be a child scope @@ -387,7 +373,7 @@ } public Indent pushIndentLogger() { - lastUsedIndent = (IndentImpl) lastUsedIndent.indent(); + lastUsedIndent = lastUsedIndent.indent(); return lastUsedIndent; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009, 2013, 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.gpu; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.nodes.*; + +/** + * Represents the output from compiling a method generated by Graal, but executing in a memory and + * computational subsystem outside the Graal host system. + * + * Output may include the compiled machine code, associated data and references, relocation + * information, deoptimization information, as this result is generated from a structure graph on + * the Graal host system. + */ +public class ExternalCompilationResult extends CompilationResult { + + private static final long serialVersionUID = 1L; + + /** + * Address of the point of entry to the external compilation result. + */ + private long entryPoint; + private StructuredGraph hostGraph; + + /** + * Set the address for the point of entry to the external compilation result. + * + * @param addr the address of the entry point + */ + public void setEntryPoint(long addr) { + entryPoint = addr; + } + + /** + * Return the address for the point of entry to the external compilation result. + * + * @return address value + */ + public long getEntryPoint() { + return entryPoint; + } + + /** + * Gets the {@linkplain #getTargetCode() code} in this compilation result as a string. + */ + public String getCodeString() { + return new String(getTargetCode(), 0, getTargetCodeSize()); + } + + public void setHostGraph(StructuredGraph hostGraph) { + this.hostGraph = hostGraph; + } + + public StructuredGraph getHostGraph() { + return hostGraph; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Sun Mar 30 16:08:33 2014 +0200 @@ -234,7 +234,7 @@ } isLeafNode = (this.inputOffsets.length == 0 && this.successorOffsets.length == 0); - nodeIterableCount = Debug.metric("NodeIterable_" + shortName); + nodeIterableCount = Debug.metric("NodeIterable_%s", shortName); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Sun Mar 30 16:08:33 2014 +0200 @@ -72,8 +72,18 @@ } @Override - public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) { - return new AMD64HotSpotLIRGenerator(graph, stub, getProviders(), getRuntime().getConfig(), frameMap, cc, lir); + public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + return new AMD64HotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); + } + + @Override + public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { + return new AMD64HotSpotLIRGenerationResult(lir, frameMap, stub); + } + + @Override + public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + return new AMD64HotSpotNodeLIRGenerator(graph, lirGenRes, lirGen); } /** @@ -192,17 +202,17 @@ } @Override - public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { + public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { // Omit the frame if the method: // - has no spill slots or other slots allocated during register allocation // - has no callee-saved registers // - has no incoming arguments passed on the stack // - has no deoptimization points // - makes no foreign calls (which require an aligned stack) - AMD64HotSpotLIRGenerator gen = (AMD64HotSpotLIRGenerator) lirGen; - FrameMap frameMap = gen.frameMap; - LIR lir = gen.lir; - assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; + AMD64HotSpotLIRGenerationResult gen = (AMD64HotSpotLIRGenerationResult) lirGenRen; + FrameMap frameMap = gen.getFrameMap(); + LIR lir = gen.getLIR(); + assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall(); Stub stub = gen.getStub(); @@ -210,14 +220,14 @@ HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null, omitFrame); CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult); crb.setFrameSize(frameMap.frameSize()); - StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot; + StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); if (deoptimizationRescueSlot != null && stub == null) { crb.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot)); } if (stub != null) { Set definedRegisters = gatherDefinedRegisters(lir); - updateStub(stub, definedRegisters, gen.calleeSaveInfo, frameMap); + updateStub(stub, definedRegisters, gen.getCalleeSaveInfo(), frameMap); } return crb; @@ -318,4 +328,5 @@ }; return new HotSpotNativeFunctionInterface(getProviders(), factory, this, config.dllLoad, config.dllLookup, config.rtldDefault); } + } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014, 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 java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.SaveRegistersOp; + +public class AMD64HotSpotLIRGenerationResult extends LIRGenerationResultBase { + + /** + * The slot reserved for storing the original return address when a frame is marked for + * deoptimization. The return address slot in the callee is overwritten with the address of a + * deoptimization stub. + */ + private StackSlot deoptimizationRescueSlot; + private final Object stub; + + /** + * Map from debug infos that need to be updated with callee save information to the operations + * that provide the information. + */ + private Map calleeSaveInfo = new HashMap<>(); + + public AMD64HotSpotLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { + super(lir, frameMap); + this.stub = stub; + } + + StackSlot getDeoptimizationRescueSlot() { + return deoptimizationRescueSlot; + } + + public final void setDeoptimizationRescueSlot(StackSlot deoptimizationRescueSlot) { + this.deoptimizationRescueSlot = deoptimizationRescueSlot; + } + + Stub getStub() { + return (Stub) stub; + } + + Map getCalleeSaveInfo() { + return calleeSaveInfo; + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,60 +24,45 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import java.lang.reflect.*; import java.util.*; import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.AMD64Address.Scale; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; -import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.CompareAndSwapCompressedOp; import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.LoadCompressedPointer; import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedConstantOp; import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.StoreCompressedPointer; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.NoOp; -import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; -import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; +import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; import com.oracle.graal.lir.amd64.AMD64Move.LoadOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp; import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; /** * LIR generator specialized for AMD64 HotSpot. */ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator { - private final HotSpotVMConfig config; + final HotSpotVMConfig config; - private final Object stub; - - protected AMD64HotSpotLIRGenerator(StructuredGraph graph, Object stub, HotSpotProviders providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); + protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); assert config.basicLockSize == 8; this.config = config; - this.stub = stub; } @Override @@ -86,13 +71,6 @@ } /** - * The slot reserved for storing the original return address when a frame is marked for - * deoptimization. The return address slot in the callee is overwritten with the address of a - * deoptimization stub. - */ - StackSlot deoptimizationRescueSlot; - - /** * Utility for emitting the instruction to save RBP. */ class SaveRbp { @@ -106,13 +84,13 @@ public SaveRbp(NoOp placeholder) { this.placeholder = placeholder; - this.reservedSlot = frameMap.allocateSpillSlot(Kind.Long); + this.reservedSlot = res.getFrameMap().allocateSpillSlot(Kind.Long); assert reservedSlot.getRawOffset() == -16 : reservedSlot.getRawOffset(); } /** * Replaces this operation with the appropriate move for saving rbp. - * + * * @param useStack specifies if rbp must be saved to the stack */ public AllocatableValue finalize(boolean useStack) { @@ -120,16 +98,16 @@ if (useStack) { dst = reservedSlot; } else { - frameMap.freeSpillSlot(reservedSlot); + res.getFrameMap().freeSpillSlot(reservedSlot); dst = newVariable(Kind.Long); } - placeholder.replace(lir, new MoveFromRegOp(dst, rbp.asValue(Kind.Long))); + placeholder.replace(res.getLIR(), new MoveFromRegOp(dst, rbp.asValue(Kind.Long))); return dst; } } - private SaveRbp saveRbp; + SaveRbp saveRbp; /** * List of epilogue operations that need to restore RBP. @@ -144,45 +122,9 @@ } } - @SuppressWarnings("hiding") - @Override - protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { - HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long); - return new HotSpotDebugInfoBuilder(nodeOperands, lockStack); - } - @Override public StackSlot getLockSlot(int lockDepth) { - return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth); - } - - @Override - protected void emitPrologue(StructuredGraph graph) { - - CallingConvention incomingArguments = cc; - - Value[] params = new Value[incomingArguments.getArgumentCount() + 1]; - for (int i = 0; i < params.length - 1; i++) { - params[i] = toStackKind(incomingArguments.getArgument(i)); - if (isStackSlot(params[i])) { - StackSlot slot = ValueUtil.asStackSlot(params[i]); - if (slot.isInCallerFrame() && !lir.hasArgInCallerFrame()) { - lir.setHasArgInCallerFrame(); - } - } - } - params[params.length - 1] = rbp.asValue(Kind.Long); - - emitIncomingValues(params); - - saveRbp = new SaveRbp(new NoOp(currentBlock, lir.lir(currentBlock).size())); - append(saveRbp.placeholder); - - for (ParameterNode param : graph.getNodes(ParameterNode.class)) { - Value paramValue = params[param.index()]; - assert paramValue.getKind() == param.kind().getStackKind(); - setResult(param, emitMove(paramValue)); - } + return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth); } private Register findPollOnReturnScratchRegister() { @@ -198,7 +140,7 @@ private Register pollOnReturnScratchRegister; @Override - protected void emitReturn(Value input) { + public void emitReturn(Value input) { if (pollOnReturnScratchRegister == null) { pollOnReturnScratchRegister = findPollOnReturnScratchRegister(); } @@ -208,14 +150,13 @@ @Override protected boolean needOnlyOopMaps() { // Stubs only need oop maps - return stub != null; + return ((AMD64HotSpotLIRGenerationResult) res).getStub() != null; } - /** - * Map from debug infos that need to be updated with callee save information to the operations - * that provide the information. - */ - Map calleeSaveInfo = new HashMap<>(); + @Override + public void emitData(AllocatableValue dst, byte[] data) { + append(new LeaDataOp(dst, data)); + } private LIRFrameState currentRuntimeCallInfo; @@ -235,8 +176,8 @@ append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save)); } - Stub getStub() { - return (Stub) stub; + public Stub getStub() { + return ((AMD64HotSpotLIRGenerationResult) res).getStub(); } @Override @@ -248,12 +189,12 @@ if (destroysRegisters) { if (getStub() != null) { if (getStub().preservesRegisters()) { - Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters(); + Register[] savedRegisters = res.getFrameMap().registerConfig.getAllocatableRegisters(); savedRegisterLocations = new StackSlot[savedRegisters.length]; for (int i = 0; i < savedRegisters.length; i++) { PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory()); assert kind != Kind.Illegal; - StackSlot spillSlot = frameMap.allocateSpillSlot(kind); + StackSlot spillSlot = res.getFrameMap().allocateSpillSlot(kind); savedRegisterLocations[i] = spillSlot; } save = emitSaveRegisters(savedRegisters, savedRegisterLocations); @@ -264,7 +205,7 @@ Variable result; if (linkage.canDeoptimize()) { - assert info != null || stub != null; + assert info != null || ((AMD64HotSpotLIRGenerationResult) res).getStub() != null; Register thread = getProviders().getRegisters().getThreadRegister(); append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread)); result = super.emitForeignCall(linkage, info, args); @@ -276,8 +217,8 @@ if (destroysRegisters) { if (getStub() != null) { if (getStub().preservesRegisters()) { - assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); - calleeSaveInfo.put(currentRuntimeCallInfo, save); + assert !((AMD64HotSpotLIRGenerationResult) res).getCalleeSaveInfo().containsKey(currentRuntimeCallInfo); + ((AMD64HotSpotLIRGenerationResult) res).getCalleeSaveInfo().put(currentRuntimeCallInfo, save); emitRestoreRegisters(save); } else { @@ -296,53 +237,18 @@ } protected boolean zapRegisters() { - Register[] zappedRegisters = frameMap.registerConfig.getAllocatableRegisters(); + Register[] zappedRegisters = res.getFrameMap().registerConfig.getAllocatableRegisters(); Constant[] zapValues = new Constant[zappedRegisters.length]; for (int i = 0; i < zappedRegisters.length; i++) { PlatformKind kind = target().arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory()); assert kind != Kind.Illegal; zapValues[i] = zapValueForKind(kind); } - calleeSaveInfo.put(currentRuntimeCallInfo, emitZapRegisters(zappedRegisters, zapValues)); + ((AMD64HotSpotLIRGenerationResult) res).getCalleeSaveInfo().put(currentRuntimeCallInfo, emitZapRegisters(zappedRegisters, zapValues)); return true; } @Override - public void visitSafepointNode(SafepointNode i) { - LIRFrameState info = state(i); - append(new AMD64HotSpotSafepointOp(info, config, this)); - } - - @SuppressWarnings("hiding") - @Override - public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { - Kind kind = x.newValue().kind(); - assert kind == x.expectedValue().kind(); - - Value expected = loadNonConst(operand(x.expectedValue())); - Variable newVal = load(operand(x.newValue())); - - int disp = 0; - AMD64AddressValue address; - Value index = operand(x.offset()); - if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) { - assert !getCodeCache().needsDataPatch(asConstant(index)); - disp += (int) ValueUtil.asConstant(index).asLong(); - address = new AMD64AddressValue(kind, load(operand(x.object())), disp); - } else { - address = new AMD64AddressValue(kind, load(operand(x.object())), load(index), Scale.Times1, disp); - } - - RegisterValue rax = AMD64.rax.asValue(kind); - emitMove(rax, expected); - append(new CompareAndSwapOp(rax, address, rax, newVal)); - - Variable result = newVariable(x.kind()); - emitMove(result, rax); - setResult(x, result); - } - - @Override public void emitTailcall(Value[] args, Value address) { append(new AMD64TailcallOp(args, address)); } @@ -350,7 +256,7 @@ @Override public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) { Value[] argLocations = new Value[args.length]; - frameMap.callsMethod(nativeCallingConvention); + res.getFrameMap().callsMethod(nativeCallingConvention); // TODO(mg): in case a native function uses floating point varargs, the ABI requires that // RAX contains the length of the varargs AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue(); @@ -366,33 +272,6 @@ } @Override - protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); - if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { - append(new AMD64HotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind)); - } else { - assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special; - HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target(); - assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method."; - Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant(); - append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod)); - } - } - - @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - if (callTarget instanceof HotSpotIndirectCallTargetNode) { - AllocatableValue metaspaceMethod = AMD64.rbx.asValue(); - emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod())); - AllocatableValue targetAddress = AMD64.rax.asValue(); - emitMove(targetAddress, operand(callTarget.computedAddress())); - append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); - } else { - super.emitIndirectCall(callTarget, result, parameters, temps, callState); - } - } - - @Override public void emitUnwind(Value exception) { ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); @@ -427,32 +306,12 @@ } @Override - public void emitPatchReturnAddress(ValueNode address) { - append(new AMD64HotSpotPatchReturnAddressOp(load(operand(address)))); - } - - @Override - public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { - Variable handler = load(operand(handlerInCallerPc)); - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); - CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); - assert outgoingCc.getArgumentCount() == 2; - RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0); - RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1); - emitMove(exceptionFixed, operand(exception)); - emitMove(exceptionPcFixed, operand(exceptionPc)); - Register thread = getProviders().getRegisters().getThreadRegister(); - AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, config.threadIsMethodHandleReturnOffset, thread); - append(op); - } - - @Override public void beforeRegisterAllocation() { super.beforeRegisterAllocation(); - boolean hasDebugInfo = lir.hasDebugInfo(); + boolean hasDebugInfo = res.getLIR().hasDebugInfo(); AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo); if (hasDebugInfo) { - deoptimizationRescueSlot = frameMap.allocateSpillSlot(Kind.Long); + ((AMD64HotSpotLIRGenerationResult) res).setDeoptimizationRescueSlot(res.getFrameMap().allocateSpillSlot(Kind.Long)); } for (AMD64HotSpotEpilogueOp op : epilogueOps) { @@ -560,38 +419,4 @@ } } - @Override - public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) { - Kind kind = node.getNewValue().kind(); - assert kind == node.getExpectedValue().kind(); - Value expected = loadNonConst(operand(node.getExpectedValue())); - Variable newValue = load(operand(node.getNewValue())); - AMD64AddressValue addressValue = asAddressValue(address); - RegisterValue raxRes = AMD64.rax.asValue(kind); - emitMove(raxRes, expected); - if (config.useCompressedOops && node.isCompressible()) { - Variable scratch = newVariable(Kind.Long); - Register heapBaseReg = getProviders().getRegisters().getHeapBaseRegister(); - append(new CompareAndSwapCompressedOp(raxRes, addressValue, raxRes, newValue, scratch, config.getOopEncoding(), heapBaseReg)); - } else { - append(new CompareAndSwapOp(raxRes, addressValue, raxRes, newValue)); - } - Variable result = newVariable(node.kind()); - append(new CondMoveOp(result, Condition.EQ, load(Constant.TRUE), Constant.FALSE)); - setResult(node, result); - } - - @Override - public void visitInfopointNode(InfopointNode i) { - if (i.getState() != null && i.getState().bci == FrameState.AFTER_BCI) { - Debug.log("Ignoring InfopointNode for AFTER_BCI"); - } else { - super.visitInfopointNode(i); - } - } - - public void emitPrefetchAllocate(ValueNode address, ValueNode distance) { - AMD64AddressValue addr = emitAddress(operand(address), 0, loadNonConst(operand(distance)), 1); - append(new AMD64PrefetchOp(addr, config.allocatePrefetchInstr)); - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,103 @@ +/* + * 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.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.compiler.amd64.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.data.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; + +/** + * Specialized code gen for comparison with compressed memory. + */ + +public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole { + public static class CompareMemoryCompressedOp extends AMD64LIRInstruction { + @Alive({COMPOSITE}) protected AMD64AddressValue x; + @Use({CONST}) protected Value y; + @State protected LIRFrameState state; + + public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) { + assert HotSpotGraalRuntime.runtime().getConfig().useCompressedOops; + this.x = x; + this.y = y; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Constant constant = (Constant) y; + if (constant.isNull()) { + masm.cmpl(x.toAddress(), 0); + } else { + if (y.getKind() == Kind.Object) { + crb.recordInlineDataInCode(new OopData(0, constant.asObject(), true)); + } else if (y.getKind() == Kind.Long) { + crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), constant.getPrimitiveAnnotation(), true)); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + masm.cmpl(x.toAddress(), 0xdeaddead); + } + } + } + + AMD64HotSpotMemoryPeephole(AMD64NodeLIRGenerator gen) { + super(gen); + } + + @Override + protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, + double trueLabelProbability) { + assert left == access || right == access; + if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) { + ValueNode other = left == access ? right : left; + Kind kind = access.nullCheckLocation().getValueKind(); + + if (other.isConstant() && kind == Kind.Object && access.isCompressible()) { + ensureEvaluated(other); + gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access))); + Condition finalCondition = right == access ? cond.mirror() : cond; + gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); + return true; + } + } + + return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; + +import java.lang.reflect.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Address.Scale; +import com.oracle.graal.compiler.amd64.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.amd64.AMD64HotSpotLIRGenerator.SaveRbp; +import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.CompareAndSwapCompressedOp; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.NoOp; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; +import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; + +/** + * LIR generator specialized for AMD64 HotSpot. + */ +public class AMD64HotSpotNodeLIRGenerator extends AMD64NodeLIRGenerator implements HotSpotNodeLIRGenerator { + + public AMD64HotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult res, LIRGenerator gen) { + super(graph, res, gen); + memoryPeephole = new AMD64HotSpotMemoryPeephole(this); + } + + private AMD64HotSpotLIRGenerator getGen() { + return (AMD64HotSpotLIRGenerator) gen; + } + + private SaveRbp getSaveRbp() { + return getGen().saveRbp; + } + + private void setSaveRbp(SaveRbp saveRbp) { + getGen().saveRbp = saveRbp; + } + + @Override + protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { + HotSpotLockStack lockStack = new HotSpotLockStack(res.getFrameMap(), Kind.Long); + return new HotSpotDebugInfoBuilder(nodeOperands, lockStack); + } + + @Override + protected void emitPrologue(StructuredGraph graph) { + + CallingConvention incomingArguments = gen.getCallingConvention(); + + Value[] params = new Value[incomingArguments.getArgumentCount() + 1]; + for (int i = 0; i < params.length - 1; i++) { + params[i] = toStackKind(incomingArguments.getArgument(i)); + if (isStackSlot(params[i])) { + StackSlot slot = ValueUtil.asStackSlot(params[i]); + if (slot.isInCallerFrame() && !res.getLIR().hasArgInCallerFrame()) { + res.getLIR().setHasArgInCallerFrame(); + } + } + } + params[params.length - 1] = rbp.asValue(Kind.Long); + + emitIncomingValues(params); + + setSaveRbp(((AMD64HotSpotLIRGenerator) gen).new SaveRbp(new NoOp(gen.getCurrentBlock(), res.getLIR().getLIRforBlock(gen.getCurrentBlock()).size()))); + append(getSaveRbp().placeholder); + + for (ParameterNode param : graph.getNodes(ParameterNode.class)) { + Value paramValue = params[param.index()]; + assert paramValue.getKind() == param.getKind().getStackKind(); + setResult(param, gen.emitMove(paramValue)); + } + } + + @Override + public void visitSafepointNode(SafepointNode i) { + LIRFrameState info = gen.state(i); + append(new AMD64HotSpotSafepointOp(info, getGen().config, this)); + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); + if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { + append(new AMD64HotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind)); + } else { + assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special; + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target(); + assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method."; + Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant(); + append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod)); + } + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + if (callTarget instanceof HotSpotIndirectCallTargetNode) { + AllocatableValue metaspaceMethod = AMD64.rbx.asValue(); + gen.emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod())); + AllocatableValue targetAddress = AMD64.rax.asValue(); + gen.emitMove(targetAddress, operand(callTarget.computedAddress())); + append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); + } else { + super.emitIndirectCall(callTarget, result, parameters, temps, callState); + } + } + + @Override + public void emitPatchReturnAddress(ValueNode address) { + append(new AMD64HotSpotPatchReturnAddressOp(gen.load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + Variable handler = gen.load(operand(handlerInCallerPc)); + ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); + assert outgoingCc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1); + gen.emitMove(exceptionFixed, operand(exception)); + gen.emitMove(exceptionPcFixed, operand(exceptionPc)); + Register thread = getGen().getProviders().getRegisters().getThreadRegister(); + AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset, + thread); + append(op); + } + + @Override + public void visitInfopointNode(InfopointNode i) { + if (i.getState() != null && i.getState().bci == FrameState.AFTER_BCI) { + Debug.log("Ignoring InfopointNode for AFTER_BCI"); + } else { + super.visitInfopointNode(i); + } + } + + public void emitPrefetchAllocate(ValueNode address, ValueNode distance) { + AMD64AddressValue addr = getGen().emitAddress(operand(address), 0, gen.loadNonConst(operand(distance)), 1); + append(new AMD64PrefetchOp(addr, getGen().config.allocatePrefetchInstr)); + } + + @Override + public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { + Kind kind = x.newValue().getKind(); + assert kind == x.expectedValue().getKind(); + + Value expected = gen.loadNonConst(operand(x.expectedValue())); + Variable newVal = gen.load(operand(x.newValue())); + + int disp = 0; + AMD64AddressValue address; + Value index = operand(x.offset()); + if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) { + assert !gen.getCodeCache().needsDataPatch(asConstant(index)); + disp += (int) ValueUtil.asConstant(index).asLong(); + address = new AMD64AddressValue(kind, gen.load(operand(x.object())), disp); + } else { + address = new AMD64AddressValue(kind, gen.load(operand(x.object())), gen.load(index), Scale.Times1, disp); + } + + RegisterValue raxLocal = AMD64.rax.asValue(kind); + gen.emitMove(raxLocal, expected); + append(new CompareAndSwapOp(raxLocal, address, raxLocal, newVal)); + + Variable result = newVariable(x.getKind()); + gen.emitMove(result, raxLocal); + setResult(x, result); + } + + @Override + public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) { + Kind kind = node.getNewValue().getKind(); + assert kind == node.getExpectedValue().getKind(); + Value expected = gen.loadNonConst(operand(node.getExpectedValue())); + Variable newValue = gen.load(operand(node.getNewValue())); + AMD64AddressValue addressValue = getGen().asAddressValue(address); + RegisterValue raxRes = AMD64.rax.asValue(kind); + gen.emitMove(raxRes, expected); + if (getGen().config.useCompressedOops && node.isCompressible()) { + Variable scratch = newVariable(Kind.Long); + Register heapBaseReg = getGen().getProviders().getRegisters().getHeapBaseRegister(); + append(new CompareAndSwapCompressedOp(raxRes, addressValue, raxRes, newValue, scratch, getGen().config.getOopEncoding(), heapBaseReg)); + } else { + append(new CompareAndSwapOp(raxRes, addressValue, raxRes, newValue)); + } + Variable result = newVariable(node.getKind()); + append(new CondMoveOp(result, Condition.EQ, gen.load(Constant.TRUE), Constant.FALSE)); + setResult(node, result); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Sun Mar 30 16:08:33 2014 +0200 @@ -48,6 +48,8 @@ */ private final Register[] callerSaved; + private final boolean allAllocatableAreCallerSaved; + private final HashMap categorized = new HashMap<>(); private final RegisterAttributes[] attributesMap; @@ -152,6 +154,7 @@ callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]); assert callerSaved.length == allocatable.length || RegisterPressure.getValue() != null; + allAllocatableAreCallerSaved = true; attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); } @@ -161,6 +164,11 @@ } @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return allAllocatableAreCallerSaved; + } + + @Override public Register getRegisterForRole(int index) { throw new UnsupportedOperationException(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java Sun Mar 30 16:08:33 2014 +0200 @@ -47,11 +47,11 @@ private final HotSpotVMConfig config; - public AMD64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) { + public AMD64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, NodeLIRGeneratorTool tool) { this.state = state; this.config = config; if (isPollingPageFar(config) || ImmutableCode.getValue()) { - temp = tool.newVariable(tool.target().wordKind); + temp = tool.getLIRGeneratorTool().newVariable(tool.getLIRGeneratorTool().target().wordKind); } else { // Don't waste a register if it's unneeded temp = Value.ILLEGAL; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -44,26 +44,27 @@ } @Override - public void generate(LIRGenerator generator) { - AMD64LIRGenerator gen = (AMD64LIRGenerator) generator; + public void generate(NodeLIRGenerator generator) { + AMD64NodeLIRGenerator gen = (AMD64NodeLIRGenerator) generator; Value[] parameter = new Value[args.count()]; JavaType[] parameterTypes = new JavaType[args.count()]; for (int i = 0; i < args.count(); i++) { parameter[i] = generator.operand(args.get(i)); - parameterTypes[i] = args.get(i).stamp().javaType(gen.getMetaAccess()); + parameterTypes[i] = args.get(i).stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess()); } - ResolvedJavaType returnType = stamp().javaType(gen.getMetaAccess()); - CallingConvention cc = generator.getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes, generator.target(), false); - gen.emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args)); - if (this.kind() != Kind.Void) { - generator.setResult(this, gen.emitMove(cc.getReturn())); + ResolvedJavaType returnType = stamp().javaType(gen.getLIRGeneratorTool().getMetaAccess()); + CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes, + generator.getLIRGeneratorTool().target(), false); + ((AMD64LIRGenerator) gen.getLIRGeneratorTool()).emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args)); + if (this.getKind() != Kind.Void) { + generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn())); } } private static int countFloatingTypeArguments(NodeInputList args) { int count = 0; for (ValueNode n : args) { - if (n.kind() == Kind.Double || n.kind() == Kind.Float) { + if (n.getKind() == Kind.Double || n.getKind() == Kind.Float) { count++; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java Sun Mar 30 16:08:33 2014 +0200 @@ -42,6 +42,7 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.printer.*; +import com.oracle.graal.gpu.*; /** * Implements compile and dispatch of Java code containing lambda constructs. Currently only used by @@ -82,7 +83,7 @@ NodeIterable calls = graph.getNodes(MethodCallTargetNode.class); assert calls.count() == 1; ResolvedJavaMethod lambdaMethod = calls.first().targetMethod(); - Debug.log("target ... " + lambdaMethod); + Debug.log("target ... %s", lambdaMethod); if (lambdaMethod == null) { Debug.log("Did not find call in accept()"); @@ -115,7 +116,7 @@ getHSAILBackend().executeKernel(code, jobSize, args); return true; } catch (InvalidInstalledCodeException iice) { - Debug.log("WARNING: Invalid installed code at exec time." + iice); + Debug.log("WARNING: Invalid installed code at exec time: %s", iice); iice.printStackTrace(); return false; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,30 +26,45 @@ import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.compiler.GraalCompiler.*; +import static com.oracle.graal.api.meta.LocationIdentity.*; import java.lang.reflect.*; import java.util.*; import com.amd.okra.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Assumptions.Assumption; import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.code.CompilationResult.Call; +import com.oracle.graal.api.code.CompilationResult.CodeAnnotation; +import com.oracle.graal.api.code.CompilationResult.DataPatch; +import com.oracle.graal.api.code.CompilationResult.ExceptionHandler; +import com.oracle.graal.api.code.CompilationResult.Infopoint; +import com.oracle.graal.api.code.CompilationResult.Mark; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.hsail.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.gpu.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hsail.*; import com.oracle.graal.java.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.hsail.*; +import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.GuardsStage; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; /** @@ -59,6 +74,8 @@ private Map paramTypeMap = new HashMap<>(); private final boolean deviceInitialized; + // TODO: get maximum Concurrency from okra + private int maxDeoptIndex = 8 * 40 * 64; // see gpu_hsail.hpp public HSAILHotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) { super(runtime, providers); @@ -79,12 +96,24 @@ /** * Initializes the GPU device. - * + * * @return whether or not initialization was successful */ private static native boolean initialize(); /** + * Control how many threads run on simulator (used only from junit tests). + */ + public void setSimulatorSingleThreaded() { + String simThrEnv = System.getenv("SIMTHREADS"); + if (simThrEnv == null || !simThrEnv.equals("1")) { + setSimulatorSingleThreaded0(); + } + } + + private static native void setSimulatorSingleThreaded0(); + + /** * Determines if the GPU device (or simulator) is available and initialized. */ public boolean isDeviceInitialized() { @@ -118,7 +147,7 @@ /** * Compiles a given method to HSAIL code. - * + * * @param makeBinary specifies whether a GPU binary should also be generated for the HSAIL code. * If true, the returned value is guaranteed to have a non-zero * {@linkplain ExternalCompilationResult#getEntryPoint() entry point}. @@ -127,13 +156,37 @@ public ExternalCompilationResult compileKernel(ResolvedJavaMethod method, boolean makeBinary) { StructuredGraph graph = new StructuredGraph(method); HotSpotProviders providers = getProviders(); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + MetaAccessProvider metaAccess = getProviders().getMetaAccess(); + + // changed this from default to help us generate deopts when needed + OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL; + optimisticOpts.remove(OptimisticOptimizations.Optimization.UseExceptionProbabilityForOperations); + new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), optimisticOpts).apply(graph); PhaseSuite graphBuilderSuite = providers.getSuites().getDefaultGraphBuilderSuite(); - graphBuilderSuite.appendPhase(new NonNullParametersPhase()); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); + + // append special HSAILNonNullParametersPhase + int numArgs = cc.getArguments().length; + graphBuilderSuite.appendPhase(new HSAILNonNullParametersPhase(numArgs)); + Suites suites = providers.getSuites().getDefaultSuites(); - ExternalCompilationResult hsailCode = compileGraph(graph, null, cc, method, providers, this, this.getTarget(), null, graphBuilderSuite, OptimisticOptimizations.NONE, getProfilingInfo(graph), - null, suites, new ExternalCompilationResult(), CompilationResultBuilderFactory.Default); + ExternalCompilationResult hsailCode = compileGraph(graph, null, cc, method, providers, this, this.getTarget(), null, graphBuilderSuite, optimisticOpts, getProfilingInfo(graph), null, suites, + new ExternalCompilationResult(), CompilationResultBuilderFactory.Default); + + // this code added to dump infopoints + try (Scope s = Debug.scope("CodeGen")) { + if (Debug.isLogEnabled()) { + // show infopoints + List infoList = hsailCode.getInfopoints(); + Debug.log("%d HSAIL infopoints", infoList.size()); + for (Infopoint info : infoList) { + Debug.log(info.toString()); + Debug.log(info.debugInfo.frame().toString()); + } + } + } catch (Throwable e) { + throw Debug.handle(e); + } if (makeBinary) { if (!deviceInitialized) { @@ -152,6 +205,26 @@ return hsailCode; } + private static class HSAILNonNullParametersPhase extends Phase { + // we use this to limit the stamping to exclude the final argument in an obj stream method + private int numArgs; + + public HSAILNonNullParametersPhase(int numArgs) { + this.numArgs = numArgs; + } + + @Override + protected void run(StructuredGraph graph) { + int argCount = 0; + for (ParameterNode param : graph.getNodes(ParameterNode.class)) { + argCount++; + if (argCount < numArgs && param.stamp() instanceof ObjectStamp) { + param.setStamp(StampFactory.declaredNonNull(((ObjectStamp) param.stamp()).type())); + } + } + } + } + /** * Generates a GPU binary from HSAIL code. */ @@ -161,23 +234,127 @@ * Installs the {@linkplain ExternalCompilationResult#getEntryPoint() GPU binary} associated * with some given HSAIL code in the code cache and returns a {@link HotSpotNmethod} handle to * the installed code. - * + * * @param hsailCode HSAIL compilation result for which a GPU binary has been generated * @return a handle to the binary as installed in the HotSpot code cache */ public final HotSpotNmethod installKernel(ResolvedJavaMethod method, ExternalCompilationResult hsailCode) { assert hsailCode.getEntryPoint() != 0L; - return getProviders().getCodeCache().addExternalMethod(method, hsailCode); + // code below here lifted from HotSpotCodeCacheProviders.addExternalMethod + // used to be return getProviders().getCodeCache().addExternalMethod(method, hsailCode); + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method; + if (hsailCode.getId() == -1) { + hsailCode.setId(javaMethod.allocateCompileId(hsailCode.getEntryBCI())); + } + CompilationResult compilationResult = hsailCode; + StructuredGraph hostGraph = hsailCode.getHostGraph(); + if (hostGraph != null) { + // TODO get rid of the unverified entry point in the host code + try (Scope ds = Debug.scope("GeneratingHostGraph")) { + HotSpotBackend hostBackend = getRuntime().getHostBackend(); + JavaType[] parameterTypes = new JavaType[hostGraph.getNodes(ParameterNode.class).count()]; + Debug.log("Param count: %d", parameterTypes.length); + for (int i = 0; i < parameterTypes.length; i++) { + ParameterNode parameter = hostGraph.getParameter(i); + Debug.log("Param [%d]=%d", i, parameter); + parameterTypes[i] = parameter.stamp().javaType(hostBackend.getProviders().getMetaAccess()); + Debug.log(" %s", parameterTypes[i]); + } + CallingConvention cc = hostBackend.getProviders().getCodeCache().getRegisterConfig().getCallingConvention(Type.JavaCallee, method.getSignature().getReturnType(null), parameterTypes, + hostBackend.getTarget(), false); + CompilationResult hostCode = compileGraph(hostGraph, null, cc, method, hostBackend.getProviders(), hostBackend, this.getTarget(), null, + hostBackend.getProviders().getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, null, null, + hostBackend.getProviders().getSuites().getDefaultSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default); + compilationResult = merge(hostCode, hsailCode); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + HotSpotNmethod code = new HotSpotNmethod(javaMethod, hsailCode.getName(), false, true); + HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(getTarget(), javaMethod, compilationResult); + CodeInstallResult result = getRuntime().getCompilerToVM().installCode(compiled, code, null); + if (result != CodeInstallResult.OK) { + return null; + } + return code; + } + + private static ExternalCompilationResult merge(CompilationResult hostCode, ExternalCompilationResult hsailCode) { + ExternalCompilationResult result = new ExternalCompilationResult(); + + // from hsail code + result.setEntryPoint(hsailCode.getEntryPoint()); + result.setId(hsailCode.getId()); + result.setEntryBCI(hsailCode.getEntryBCI()); + assert hsailCode.getMarks().isEmpty(); + assert hsailCode.getExceptionHandlers().isEmpty(); + assert hsailCode.getDataReferences().isEmpty(); + + // from host code + result.setFrameSize(hostCode.getFrameSize()); + result.setCustomStackAreaOffset(hostCode.getCustomStackAreaOffset()); + result.setRegisterRestoreEpilogueOffset(hostCode.getRegisterRestoreEpilogueOffset()); + result.setTargetCode(hostCode.getTargetCode(), hostCode.getTargetCodeSize()); + for (CodeAnnotation annotation : hostCode.getAnnotations()) { + result.addAnnotation(annotation); + } + CompilationResult.Mark[] noMarks = {}; + for (Mark mark : hostCode.getMarks()) { + result.recordMark(mark.pcOffset, mark.id, noMarks); + } + for (ExceptionHandler handler : hostCode.getExceptionHandlers()) { + result.recordExceptionHandler(handler.pcOffset, handler.handlerPos); + } + for (DataPatch patch : hostCode.getDataReferences()) { + if (patch.data != null) { + if (patch.inline) { + result.recordInlineData(patch.pcOffset, patch.data); + } else { + result.recordDataReference(patch.pcOffset, patch.data); + } + } + } + for (Infopoint infopoint : hostCode.getInfopoints()) { + if (infopoint instanceof Call) { + Call call = (Call) infopoint; + result.recordCall(call.pcOffset, call.size, call.target, call.debugInfo, call.direct); + } else { + result.recordInfopoint(infopoint.pcOffset, infopoint.debugInfo, infopoint.reason); + } + } + + // merged + Assumptions mergedAssumptions = new Assumptions(true); + if (hostCode.getAssumptions() != null) { + for (Assumption assumption : hostCode.getAssumptions().getAssumptions()) { + if (assumption != null) { + mergedAssumptions.record(assumption); + } + } + } + if (hsailCode.getAssumptions() != null) { + for (Assumption assumption : hsailCode.getAssumptions().getAssumptions()) { + if (assumption != null) { + mergedAssumptions.record(assumption); + } + } + } + if (!mergedAssumptions.isEmpty()) { + result.setAssumptions(mergedAssumptions); + } + return result; } public boolean executeKernel(HotSpotInstalledCode kernel, int jobSize, Object[] args) throws InvalidInstalledCodeException { if (!deviceInitialized) { throw new GraalInternalError("Cannot execute GPU kernel if device is not initialized"); } - return executeKernel0(kernel, jobSize, args); + Object[] oopsSaveArea = new Object[maxDeoptIndex * 16]; + return executeKernel0(kernel, jobSize, args, oopsSaveArea); } - private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args) throws InvalidInstalledCodeException; + private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Object[] oopsSave) throws InvalidInstalledCodeException; /** * Use the HSAIL register set when the compilation target is HSAIL. @@ -188,8 +365,18 @@ } @Override - public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) { - return new HSAILHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir); + public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + return new HSAILHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); + } + + @Override + public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { + return new HSAILHotSpotLIRGenerationResult(lir, frameMap); + } + + @Override + public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + return new HSAILHotSpotNodeLIRGenerator(graph, lirGenRes, lirGen); } class HotSpotFrameContext implements FrameContext { @@ -209,17 +396,32 @@ } } + /** + * a class to allow us to save lirGen. + */ + static class HSAILCompilationResultBuilder extends CompilationResultBuilder { + public HSAILHotSpotLIRGenerationResult lirGenRes; + + public HSAILCompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext, + CompilationResult compilationResult, HSAILHotSpotLIRGenerationResult lirGenRes) { + super(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult); + this.lirGenRes = lirGenRes; + } + } + @Override protected Assembler createAssembler(FrameMap frameMap) { return new HSAILAssembler(getTarget()); } @Override - public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { - FrameMap frameMap = lirGen.frameMap; + public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { + FrameMap frameMap = lirGenRes.getFrameMap(); Assembler masm = createAssembler(frameMap); HotSpotFrameContext frameContext = new HotSpotFrameContext(); - CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult); + // save lirGen for later use by setHostGraph + CompilationResultBuilder crb = new HSAILCompilationResultBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult, + (HSAILHotSpotLIRGenerationResult) lirGenRes); crb.setFrameSize(frameMap.frameSize()); return crb; } @@ -227,10 +429,12 @@ @Override public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod method) { assert method != null : lir + " is not associated with a method"; + + boolean usesDeoptInfo = true; // TODO: make this conditional on something? + // Emit the prologue. - Assembler asm = crb.asm; - asm.emitString0("version 0:95: $full : $large;"); - asm.emitString(""); + HSAILAssembler asm = (HSAILAssembler) crb.asm; + asm.emitString0("version 0:95: $full : $large;\n"); Signature signature = method.getSignature(); int sigParamCount = signature.getParameterCount(false); @@ -275,10 +479,8 @@ } } - asm.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method); - asm.emitString(""); - asm.emitString0("kernel &run ("); - asm.emitString(""); + asm.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method + "\n"); + asm.emitString0("kernel &run ( \n"); FrameMap frameMap = crb.frameMap; RegisterConfig regConfig = frameMap.registerConfig; @@ -297,7 +499,7 @@ /** * Compute the hsail size mappings up to but not including the last non-constant parameter * (which is the gid). - * + * */ String[] paramHsailSizes = new String[totalParamCount]; for (int i = 0; i < totalParamCount; i++) { @@ -310,11 +512,17 @@ for (int i = 0; i < totalParamCount; i++) { String str = "align 8 kernarg_" + paramHsailSizes[i] + " " + paramNames[i]; - if (i != totalParamCount - 1) { + if (usesDeoptInfo || (i != totalParamCount - 1)) { str += ","; } asm.emitString(str); } + + if (usesDeoptInfo) { + // add in the deoptInfo parameter + asm.emitString("kernarg_u64 " + asm.getDeoptInfoName()); + } + asm.emitString(") {"); /* @@ -333,10 +541,28 @@ String workItemReg = "$s" + Integer.toString(asRegister(cc.getArgument(nonConstantParamCount)).encoding()); asm.emitString("workitemabsid_u32 " + workItemReg + ", 0;"); + final int offsetToDeoptSaveStates = getRuntime().getConfig().hsailSaveStatesOffset0; + final int sizeofKernelDeopt = getRuntime().getConfig().hsailSaveStatesOffset1 - getRuntime().getConfig().hsailSaveStatesOffset0; + final int offsetToDeopt = getRuntime().getConfig().hsailDeoptOffset; + final int offsetToNeverRanArray = getRuntime().getConfig().hsailNeverRanArrayOffset; + final int offsetToDeoptNextIndex = getRuntime().getConfig().hsailDeoptNextIndexOffset; + final String deoptInProgressLabel = "@LHandleDeoptInProgress"; + + if (usesDeoptInfo) { + AllocatableValue scratch64 = HSAIL.d16.asValue(Kind.Object); + AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int); + HSAILAddress deoptInfoAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeopt).toAddress(); + asm.emitLoadKernelArg(scratch64, asm.getDeoptInfoName(), "u64"); + asm.emitComment("// Check if a deopt has occurred and abort if true before doing any work"); + asm.emitLoadAcquire(scratch32, deoptInfoAddr); + asm.emitCompare(scratch32, Constant.forInt(0), "ne", false, false); + asm.cbr(deoptInProgressLabel); + } + /* * Note the logic used for this spillseg size is to leave space and then go back and patch * in the correct size once we have generated all the instructions. This should probably be - * done in a more robust way by implementing something like codeBuffer.insertString. + * done in a more robust way by implementing something like asm.insertString. */ int spillsegDeclarationPosition = asm.position() + 1; String spillsegTemplate = "align 4 spill_u8 %spillseg[123456];"; @@ -373,9 +599,14 @@ if (narrowOopBase == 0) { asm.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift"); } else if (narrowOopShift == 0) { + // not sure if we ever get add with 0 shift but just in case + asm.emitString("cmp_eq_b1_u64 $c0, " + tmpReg + ", 0x0; // avoid add if compressed is null"); asm.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase"); + asm.emitString("cmov_b64 " + iterationObjArgReg + ", $c0, 0x0, " + iterationObjArgReg + "; // avoid add if compressed is null"); } else { + asm.emitString("cmp_eq_b1_u64 $c0, " + tmpReg + ", 0x0; // avoid shift-add if compressed is null"); asm.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase"); + asm.emitString("cmov_b64 " + iterationObjArgReg + ", $c0, 0x0, " + iterationObjArgReg + "; // avoid shift-add if compressed is null"); } } @@ -397,9 +628,289 @@ spillsegStringFinal = spillsegTemplate.replace("123456", String.format("%6d", maxStackSize)); } asm.emitString(spillsegStringFinal, spillsegDeclarationPosition); + // Emit the epilogue. - // Emit the epilogue. - asm.emitString0("};"); - asm.emitString(""); + final int offsetToDeoptimizationWorkItem = getRuntime().getConfig().hsailDeoptimizationWorkItem; + final int offsetToDeoptimizationReason = getRuntime().getConfig().hsailDeoptimizationReason; + final int offsetToDeoptimizationFrame = getRuntime().getConfig().hsailDeoptimizationFrame; + final int offsetToFramePc = getRuntime().getConfig().hsailFramePcOffset; + final int offsetToNumSaves = getRuntime().getConfig().hsailFrameNumSRegOffset; + final int offsetToSaveArea = getRuntime().getConfig().hsailFrameSaveAreaOffset; + + // TODO: keep track of whether we need it + if (usesDeoptInfo) { + AllocatableValue scratch64 = HSAIL.d16.asValue(Kind.Object); + AllocatableValue cuSaveAreaPtr = HSAIL.d17.asValue(Kind.Object); + AllocatableValue waveMathScratch1 = HSAIL.d18.asValue(Kind.Object); + AllocatableValue waveMathScratch2 = HSAIL.d19.asValue(Kind.Object); + + AllocatableValue actionAndReasonReg = HSAIL.s32.asValue(Kind.Int); + AllocatableValue codeBufferOffsetReg = HSAIL.s33.asValue(Kind.Int); + AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int); + AllocatableValue workidreg = HSAIL.s35.asValue(Kind.Int); + AllocatableValue dregOopMapReg = HSAIL.s39.asValue(Kind.Int); + + HSAILAddress deoptNextIndexAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptNextIndex).toAddress(); + HSAILAddress neverRanArrayAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToNeverRanArray).toAddress(); + + // The just-started lanes that see the deopt flag will jump here + asm.emitString0(deoptInProgressLabel + ":\n"); + asm.emitLoad(Kind.Object, waveMathScratch1, neverRanArrayAddr); + asm.emitWorkItemAbsId(workidreg); + asm.emitConvert(waveMathScratch2, workidreg, Kind.Object, Kind.Int); + asm.emit("add", waveMathScratch1, waveMathScratch1, waveMathScratch2); + HSAILAddress neverRanStoreAddr = new HSAILAddressValue(Kind.Byte, waveMathScratch1, 0).toAddress(); + asm.emitStore(Kind.Byte, Constant.forInt(1), neverRanStoreAddr); + asm.emitString("ret;"); + + // The deoptimizing lanes will jump here + asm.emitString0(asm.getDeoptLabelName() + ":\n"); + String labelExit = asm.getDeoptLabelName() + "_Exit"; + + HSAILAddress deoptInfoAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeopt).toAddress(); + asm.emitLoadKernelArg(scratch64, asm.getDeoptInfoName(), "u64"); + + // Set deopt occurred flag + asm.emitMov(scratch32, Constant.forInt(1)); + asm.emitStoreRelease(scratch32, deoptInfoAddr); + + asm.emitComment("// Determine next deopt save slot"); + asm.emitAtomicAdd(scratch32, deoptNextIndexAddr, Constant.forInt(1)); + // scratch32 now holds next index to use + // set error condition if no room in save area + asm.emitComment("// assert room to save deopt"); + asm.emitCompare(scratch32, Constant.forInt(maxDeoptIndex), "lt", false, false); + asm.cbr("@L_StoreDeopt"); + // if assert fails, store a guaranteed negative workitemid in top level deopt occurred + // flag + asm.emitWorkItemAbsId(scratch32); + asm.emit("mad", scratch32, scratch32, Constant.forInt(-1), Constant.forInt(-1)); + asm.emitStore(scratch32, deoptInfoAddr); + asm.emitString("ret;"); + + asm.emitString0("@L_StoreDeopt" + ":\n"); + + // Store deopt for this workitem into its slot in the HSAILComputeUnitSaveStates array + + asm.emitComment("// Convert id's for ptr math"); + asm.emitConvert(cuSaveAreaPtr, scratch32, Kind.Object, Kind.Int); + asm.emitComment("// multiply by sizeof KernelDeoptArea"); + asm.emit("mul", cuSaveAreaPtr, cuSaveAreaPtr, Constant.forInt(sizeofKernelDeopt)); + asm.emitComment("// Add computed offset to deoptInfoPtr base"); + asm.emit("add", cuSaveAreaPtr, cuSaveAreaPtr, scratch64); + // Add offset to _deopt_save_states[0] + asm.emit("add", scratch64, cuSaveAreaPtr, Constant.forInt(offsetToDeoptSaveStates)); + + HSAILAddress workItemAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptimizationWorkItem).toAddress(); + HSAILAddress actionReasonStoreAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptimizationReason).toAddress(); + + asm.emitComment("// Get _deopt_info._first_frame"); + asm.emit("add", waveMathScratch1, scratch64, Constant.forInt(offsetToDeoptimizationFrame)); + // Now scratch64 is the _deopt_info._first_frame + HSAILAddress pcStoreAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToFramePc).toAddress(); + HSAILAddress regCountsAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToNumSaves).toAddress(); + HSAILAddress dregOopMapAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToNumSaves + 2).toAddress(); + + asm.emitComment("// store deopting workitem"); + asm.emitWorkItemAbsId(scratch32); + asm.emitStore(Kind.Int, scratch32, workItemAddr); + asm.emitComment("// store actionAndReason"); + asm.emitStore(Kind.Int, actionAndReasonReg, actionReasonStoreAddr); + asm.emitComment("// store PC"); + asm.emitStore(Kind.Int, codeBufferOffsetReg, pcStoreAddr); + asm.emitComment("// store regCounts"); + asm.emitStore(Kind.Short, Constant.forInt(32 + (16 << 8) + (0 << 16)), regCountsAddr); + asm.emitComment("// store dreg ref map bits"); + asm.emitStore(Kind.Short, dregOopMapReg, dregOopMapAddr); + + // get the union of registers needed to be saved at the infopoints + // usedRegs array assumes d15 has the highest register number we wish to save + // and initially has all registers as false + boolean[] infoUsedRegs = new boolean[HSAIL.d15.number + 1]; + List infoList = crb.compilationResult.getInfopoints(); + for (Infopoint info : infoList) { + BytecodeFrame frame = info.debugInfo.frame(); + for (int i = 0; i < frame.numLocals + frame.numStack; i++) { + Value val = frame.values[i]; + if (isLegal(val) && isRegister(val)) { + Register reg = asRegister(val); + infoUsedRegs[reg.number] = true; + } + } + } + + // loop storing each of the 32 s registers that are used by infopoints + // we always store in a fixed location, even if some registers are not stored + asm.emitComment("// store used s regs"); + int ofst = offsetToSaveArea; + for (Register sreg : HSAIL.sRegisters) { + if (infoUsedRegs[sreg.number]) { + Kind kind = Kind.Int; + HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress(); + AllocatableValue sregValue = sreg.asValue(kind); + asm.emitStore(kind, sregValue, addr); + } + ofst += 4; + } + + // loop storing each of the 16 d registers that are used by infopoints + asm.emitComment("// store used d regs"); + for (Register dreg : HSAIL.dRegisters) { + if (infoUsedRegs[dreg.number]) { + Kind kind = Kind.Long; + HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress(); + AllocatableValue dregValue = dreg.asValue(kind); + asm.emitStore(kind, dregValue, addr); + } + ofst += 8; + } + + // for now, ignore saving the spill variables but that would come here + + asm.emitString0(labelExit + ":\n"); + + // and emit the return + crb.frameContext.leave(crb); + asm.exit(); + } + + asm.emitString0("}; \n"); + + ExternalCompilationResult compilationResult = (ExternalCompilationResult) crb.compilationResult; + HSAILHotSpotLIRGenerationResult lirGenRes = ((HSAILCompilationResultBuilder) crb).lirGenRes; + compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), getRuntime().getConfig())); } + + private static StructuredGraph prepareHostGraph(ResolvedJavaMethod method, List deopts, HotSpotProviders providers, HotSpotVMConfig config) { + if (deopts.isEmpty()) { + return null; + } + StructuredGraph hostGraph = new StructuredGraph(method, -2); + ParameterNode deoptId = hostGraph.unique(new ParameterNode(0, StampFactory.intValue())); + ParameterNode hsailFrame = hostGraph.unique(new ParameterNode(1, StampFactory.forKind(providers.getCodeCache().getTarget().wordKind))); + ParameterNode reasonAndAction = hostGraph.unique(new ParameterNode(2, StampFactory.intValue())); + ParameterNode speculation = hostGraph.unique(new ParameterNode(3, StampFactory.object())); + AbstractBeginNode[] branches = new AbstractBeginNode[deopts.size() + 1]; + int[] keys = new int[deopts.size()]; + int[] keySuccessors = new int[deopts.size() + 1]; + double[] keyProbabilities = new double[deopts.size() + 1]; + int i = 0; + Collections.sort(deopts, new Comparator() { + public int compare(DeoptimizeOp o1, DeoptimizeOp o2) { + return o1.getCodeBufferPos() - o2.getCodeBufferPos(); + } + }); + for (DeoptimizeOp deopt : deopts) { + keySuccessors[i] = i; + keyProbabilities[i] = 1.0 / deopts.size(); + keys[i] = deopt.getCodeBufferPos(); + assert keys[i] >= 0; + branches[i] = createHostDeoptBranch(deopt, hsailFrame, reasonAndAction, speculation, providers, config); + + i++; + } + keyProbabilities[deopts.size()] = 0; // default + keySuccessors[deopts.size()] = deopts.size(); + branches[deopts.size()] = createHostCrashBranch(hostGraph, deoptId); + IntegerSwitchNode switchNode = hostGraph.add(new IntegerSwitchNode(deoptId, branches, keys, keyProbabilities, keySuccessors)); + StartNode start = hostGraph.start(); + start.setNext(switchNode); + /* + * printf.setNext(printf2); printf2.setNext(switchNode); + */ + hostGraph.setGuardsStage(GuardsStage.AFTER_FSA); + return hostGraph; + } + + private static AbstractBeginNode createHostCrashBranch(StructuredGraph hostGraph, ValueNode deoptId) { + VMErrorNode vmError = hostGraph.add(new VMErrorNode("Error in HSAIL deopt. DeoptId=%d", deoptId)); + // ConvertNode.convert(hostGraph, Kind.Long, deoptId))); + vmError.setNext(hostGraph.add(new ReturnNode(ConstantNode.defaultForKind(hostGraph.method().getSignature().getReturnKind(), hostGraph)))); + return BeginNode.begin(vmError); + } + + private static AbstractBeginNode createHostDeoptBranch(DeoptimizeOp deopt, ParameterNode hsailFrame, ValueNode reasonAndAction, ValueNode speculation, HotSpotProviders providers, + HotSpotVMConfig config) { + BeginNode branch = hsailFrame.graph().add(new BeginNode()); + DynamicDeoptimizeNode deoptimization = hsailFrame.graph().add(new DynamicDeoptimizeNode(reasonAndAction, speculation)); + deoptimization.setStateBefore(createFrameState(deopt.getFrameState().topFrame, hsailFrame, providers, config)); + branch.setNext(deoptimization); + return branch; + } + + private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config) { + StructuredGraph hostGraph = hsailFrame.graph(); + ValueNode[] locals = new ValueNode[lowLevelFrame.numLocals]; + for (int i = 0; i < lowLevelFrame.numLocals; i++) { + locals[i] = getNodeForValueFromFrame(lowLevelFrame.getLocalValue(i), hsailFrame, hostGraph, providers, config); + } + List stack = new ArrayList<>(lowLevelFrame.numStack); + for (int i = 0; i < lowLevelFrame.numStack; i++) { + stack.add(getNodeForValueFromFrame(lowLevelFrame.getStackValue(i), hsailFrame, hostGraph, providers, config)); + } + ValueNode[] locks = new ValueNode[lowLevelFrame.numLocks]; + MonitorIdNode[] monitorIds = new MonitorIdNode[lowLevelFrame.numLocks]; + for (int i = 0; i < lowLevelFrame.numLocks; i++) { + HotSpotMonitorValue lockValue = (HotSpotMonitorValue) lowLevelFrame.getLockValue(i); + locks[i] = getNodeForValueFromFrame(lockValue, hsailFrame, hostGraph, providers, config); + monitorIds[i] = getMonitorIdForHotSpotMonitorValueFromFrame(lockValue, hsailFrame, hostGraph); + } + FrameState frameState = hostGraph.add(new FrameState(lowLevelFrame.getMethod(), lowLevelFrame.getBCI(), locals, stack, locks, monitorIds, lowLevelFrame.rethrowException, false)); + if (lowLevelFrame.caller() != null) { + frameState.setOuterFrameState(createFrameState(lowLevelFrame.caller(), hsailFrame, providers, config)); + } + return frameState; + } + + @SuppressWarnings({"unused"}) + private static MonitorIdNode getMonitorIdForHotSpotMonitorValueFromFrame(HotSpotMonitorValue lockValue, ParameterNode hsailFrame, StructuredGraph hsailGraph) { + if (lockValue.isEliminated()) { + return null; + } + throw GraalInternalError.unimplemented(); + } + + private static ValueNode getNodeForValueFromFrame(Value localValue, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) { + ValueNode valueNode; + if (localValue instanceof Constant) { + valueNode = ConstantNode.forConstant((Constant) localValue, providers.getMetaAccess(), hostGraph); + } else if (localValue instanceof VirtualObject) { + throw GraalInternalError.unimplemented(); + } else if (localValue instanceof StackSlot) { + throw GraalInternalError.unimplemented(); + } else if (localValue instanceof HotSpotMonitorValue) { + HotSpotMonitorValue hotSpotMonitorValue = (HotSpotMonitorValue) localValue; + return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config); + } else if (localValue instanceof RegisterValue) { + RegisterValue registerValue = (RegisterValue) localValue; + int regNumber = registerValue.getRegister().number; + valueNode = getNodeForRegisterFromFrame(regNumber, localValue.getKind(), hsailFrame, hostGraph, providers, config); + } else if (Value.ILLEGAL.equals(localValue)) { + valueNode = null; + } else { + throw GraalInternalError.shouldNotReachHere(); + } + return valueNode; + } + + private static ValueNode getNodeForRegisterFromFrame(int regNumber, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) { + ValueNode valueNode; + LocationNode location; + if (regNumber >= HSAIL.s0.number && regNumber <= HSAIL.s31.number) { + int intSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Int); + long offset = config.hsailFrameSaveAreaOffset + intSize * (regNumber - HSAIL.s0.number); + location = ConstantLocationNode.create(FINAL_LOCATION, valueKind, offset, hostGraph); + } else if (regNumber >= HSAIL.d0.number && regNumber <= HSAIL.d15.number) { + int longSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Long); + long offset = config.hsailFrameSaveAreaOffset + longSize * (regNumber - HSAIL.d0.number); + LocationNode numSRegsLocation = ConstantLocationNode.create(FINAL_LOCATION, Kind.Byte, config.hsailFrameNumSRegOffset, hostGraph); + ValueNode numSRegs = hostGraph.unique(new FloatingReadNode(hsailFrame, numSRegsLocation, null, StampFactory.forKind(Kind.Byte))); + location = IndexedLocationNode.create(FINAL_LOCATION, valueKind, offset, numSRegs, hostGraph, 4); + } else { + throw GraalInternalError.shouldNotReachHere("unknown hsail register: " + regNumber); + } + valueNode = hostGraph.unique(new FloatingReadNode(hsailFrame, location, null, StampFactory.forKind(valueKind))); + return valueNode; + } + } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerationResult.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, 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.hsail; + +import java.util.*; + +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp; + +public class HSAILHotSpotLIRGenerationResult extends LIRGenerationResultBase { + + private List deopts = new ArrayList<>(); + + public HSAILHotSpotLIRGenerationResult(LIR lir, FrameMap frameMap) { + super(lir, frameMap); + } + + public List getDeopts() { + return deopts; + } + + public void addDeopt(DeoptimizeOp deopt) { + deopts.add(deopt); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,58 +23,69 @@ package com.oracle.graal.hotspot.hsail; -import sun.misc.*; +import static com.oracle.graal.api.code.ValueUtil.*; import com.oracle.graal.api.code.*; -import static com.oracle.graal.api.code.ValueUtil.asConstant; -import static com.oracle.graal.api.code.ValueUtil.isConstant; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.hsail.*; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.hsail.*; -import com.oracle.graal.lir.hsail.HSAILControlFlow.*; -import com.oracle.graal.lir.hsail.HSAILMove.*; -import com.oracle.graal.phases.util.*; +import com.oracle.graal.lir.hsail.HSAILControlFlow.DeoptimizeOp; +import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall1ArgOp; +import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall2ArgOp; +import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCallNoArgOp; +import com.oracle.graal.lir.hsail.HSAILMove.LoadCompressedPointer; +import com.oracle.graal.lir.hsail.HSAILMove.LoadOp; +import com.oracle.graal.lir.hsail.HSAILMove.StoreCompressedPointer; +import com.oracle.graal.lir.hsail.HSAILMove.StoreConstantOp; +import com.oracle.graal.lir.hsail.HSAILMove.StoreOp; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.graph.*; +import com.oracle.graal.phases.util.*; /** * The HotSpot specific portion of the HSAIL LIR generator. */ public class HSAILHotSpotLIRGenerator extends HSAILLIRGenerator { - private final HotSpotVMConfig config; + final HotSpotVMConfig config; - public HSAILHotSpotLIRGenerator(StructuredGraph graph, Providers providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); + public HSAILHotSpotLIRGenerator(Providers providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); this.config = config; } - private int getLogMinObjectAlignment() { + @Override + public HotSpotProviders getProviders() { + return (HotSpotProviders) super.getProviders(); + } + + int getLogMinObjectAlignment() { return config.logMinObjAlignment(); } - private int getNarrowOopShift() { + int getNarrowOopShift() { return config.narrowOopShift; } - private long getNarrowOopBase() { + long getNarrowOopBase() { return config.narrowOopBase; } - private int getLogKlassAlignment() { + int getLogKlassAlignment() { return config.logKlassAlignment; } - private int getNarrowKlassShift() { + int getNarrowKlassShift() { return config.narrowKlassShift; } - private long getNarrowKlassBase() { + long getNarrowKlassBase() { return config.narrowKlassBase; } @@ -88,41 +99,6 @@ } /** - * Appends either a {@link CompareAndSwapOp} or a {@link CompareAndSwapCompressedOp} depending - * on whether the memory location of a given {@link LoweredCompareAndSwapNode} contains a - * compressed oop. For the {@link CompareAndSwapCompressedOp} case, allocates a number of - * scratch registers. The result {@link #operand(ValueNode) operand} for {@code node} complies - * with the API for {@link Unsafe#compareAndSwapInt(Object, long, int, int)}. - * - * @param address the memory location targeted by the operation - */ - @Override - public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) { - Kind kind = node.getNewValue().kind(); - assert kind == node.getExpectedValue().kind(); - Variable expected = load(operand(node.getExpectedValue())); - Variable newValue = load(operand(node.getNewValue())); - HSAILAddressValue addressValue = asAddressValue(address); - Variable casResult = newVariable(kind); - if (config.useCompressedOops && node.isCompressible()) { - // make 64-bit scratch variables for expected and new - Variable scratchExpected64 = newVariable(Kind.Long); - Variable scratchNewValue64 = newVariable(Kind.Long); - // make 32-bit scratch variables for expected and new and result - Variable scratchExpected32 = newVariable(Kind.Int); - Variable scratchNewValue32 = newVariable(Kind.Int); - Variable scratchCasResult32 = newVariable(Kind.Int); - append(new CompareAndSwapCompressedOp(casResult, addressValue, expected, newValue, scratchExpected64, scratchNewValue64, scratchExpected32, scratchNewValue32, scratchCasResult32, - getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment())); - } else { - append(new CompareAndSwapOp(casResult, addressValue, expected, newValue)); - } - Variable nodeResult = newVariable(node.kind()); - append(new CondMoveOp(mapKindToCompareOp(kind), casResult, expected, nodeResult, Condition.EQ, Constant.INT_1, Constant.INT_0)); - setResult(node, nodeResult); - } - - /** * Returns whether or not the input access should be (de)compressed. */ private boolean isCompressedOperation(Kind kind, Access access) { @@ -163,6 +139,9 @@ if (isCompressed) { if ((c.getKind() == Kind.Object) && c.isNull()) { append(new StoreConstantOp(Kind.Int, storeAddress, Constant.forInt(0), state)); + } else if (c.getKind() == Kind.Long) { + Constant value = compress(c, config.getKlassEncoding()); + append(new StoreConstantOp(Kind.Int, storeAddress, value, state)); } else { throw GraalInternalError.shouldNotReachHere("can't handle: " + access); } @@ -185,11 +164,25 @@ } } + @Override + public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting) { + emitDeoptimizeInner(actionAndReason, state(deopting), "emitDeoptimize"); + } + + /*** + * We need 64-bit and 32-bit scratch registers for the codegen $s0 can be live at this block. + */ + private void emitDeoptimizeInner(Value actionAndReason, LIRFrameState lirFrameState, String emitName) { + DeoptimizeOp deopt = new DeoptimizeOp(actionAndReason, lirFrameState, emitName, getMetaAccess()); + ((HSAILHotSpotLIRGenerationResult) res).addDeopt(deopt); + append(deopt); + } + /*** * This is a very temporary solution to emitForeignCall. We don't really support foreign calls * yet, but we do want to generate dummy code for them. The ForeignCallXXXOps just end up * emitting a comment as to what Foreign call they would have made. - **/ + */ @Override public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) { Variable result = newVariable(Kind.Object); // linkage.getDescriptor().getResultType()); @@ -226,4 +219,14 @@ // this version of emitForeignCall not used for now } + /** + * @return a compressed version of the incoming constant lifted from AMD64HotSpotLIRGenerator + */ + protected static Constant compress(Constant c, CompressEncoding encoding) { + if (c.getKind() == Kind.Long) { + return Constant.forIntegerKind(Kind.Int, (int) (((c.asLong() - encoding.base) >> encoding.shift) & 0xffffffffL), c.getPrimitiveAnnotation()); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLoweringProvider.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,21 +27,92 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import java.util.HashMap; public class HSAILHotSpotLoweringProvider extends HotSpotLoweringProvider { + abstract static class LoweringStrategy { + abstract void lower(Node n, LoweringTool tool); + } + + static LoweringStrategy PassThruStrategy = new LoweringStrategy() { + @Override + void lower(Node n, LoweringTool tool) { + return; + } + }; + + static LoweringStrategy RejectStrategy = new LoweringStrategy() { + @Override + void lower(Node n, LoweringTool tool) { + throw new GraalInternalError("Node implementing Lowerable not handled in HSAIL Backend: " + n); + } + }; + + // strategy to replace an UnwindNode with a DeoptNode + static LoweringStrategy UnwindNodeStrategy = new LoweringStrategy() { + @Override + void lower(Node n, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) n.graph(); + UnwindNode unwind = (UnwindNode) n; + ValueNode exception = unwind.exception(); + if (exception instanceof ForeignCallNode) { + // build up action and reason + String callName = ((ForeignCallNode) exception).getDescriptor().getName(); + DeoptimizationReason reason; + switch (callName) { + case "createOutOfBoundsException": + reason = DeoptimizationReason.BoundsCheckException; + break; + case "createNullPointerException": + reason = DeoptimizationReason.NullCheckException; + break; + default: + reason = DeoptimizationReason.None; + } + unwind.replaceAtPredecessor(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, reason))); + unwind.safeDelete(); + } else { + // unwind whose exception is not an instance of ForeignCallNode + throw new GraalInternalError("UnwindNode seen without ForeignCallNode: " + exception); + } + } + }; + + private static HashMap, LoweringStrategy> strategyMap = new HashMap<>(); + static { + strategyMap.put(ConvertNode.class, PassThruStrategy); + strategyMap.put(FloatConvertNode.class, PassThruStrategy); + strategyMap.put(NewInstanceNode.class, RejectStrategy); + strategyMap.put(NewArrayNode.class, RejectStrategy); + strategyMap.put(NewMultiArrayNode.class, RejectStrategy); + strategyMap.put(DynamicNewArrayNode.class, RejectStrategy); + strategyMap.put(MonitorEnterNode.class, RejectStrategy); + strategyMap.put(MonitorExitNode.class, RejectStrategy); + strategyMap.put(UnwindNode.class, UnwindNodeStrategy); + } + + private static LoweringStrategy getStrategy(Node n) { + return strategyMap.get(n.getClass()); + } + public HSAILHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers) { super(runtime, metaAccess, foreignCalls, registers); } @Override public void lower(Node n, LoweringTool tool) { - if (n instanceof ConvertNode) { - return; + LoweringStrategy strategy = getStrategy(n); + // if not in map, let superclass handle it + if (strategy == null) { + super.lower(n, tool); } else { - super.lower(n, tool); + strategy.lower(n, tool); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013, 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.hsail; + +import sun.misc.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.hsail.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.hsail.*; +import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp; +import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapCompressedOp; +import com.oracle.graal.lir.hsail.HSAILMove.CompareAndSwapOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; + +/** + * The HotSpot specific portion of the HSAIL LIR generator. + */ +public class HSAILHotSpotNodeLIRGenerator extends HSAILNodeLIRGenerator { + + public HSAILHotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + super(graph, lirGenRes, lirGen); + } + + private HSAILHotSpotLIRGenerator getGen() { + return (HSAILHotSpotLIRGenerator) gen; + } + + /** + * Appends either a {@link CompareAndSwapOp} or a {@link CompareAndSwapCompressedOp} depending + * on whether the memory location of a given {@link LoweredCompareAndSwapNode} contains a + * compressed oop. For the {@link CompareAndSwapCompressedOp} case, allocates a number of + * scratch registers. The result {@link #operand(ValueNode) operand} for {@code node} complies + * with the API for {@link Unsafe#compareAndSwapInt(Object, long, int, int)}. + * + * @param address the memory location targeted by the operation + */ + @Override + public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) { + Kind kind = node.getNewValue().getKind(); + assert kind == node.getExpectedValue().getKind(); + Variable expected = gen.load(operand(node.getExpectedValue())); + Variable newValue = gen.load(operand(node.getNewValue())); + HSAILAddressValue addressValue = getGen().asAddressValue(address); + Variable casResult = newVariable(kind); + if (getGen().config.useCompressedOops && node.isCompressible()) { + // make 64-bit scratch variables for expected and new + Variable scratchExpected64 = newVariable(Kind.Long); + Variable scratchNewValue64 = newVariable(Kind.Long); + // make 32-bit scratch variables for expected and new and result + Variable scratchExpected32 = newVariable(Kind.Int); + Variable scratchNewValue32 = newVariable(Kind.Int); + Variable scratchCasResult32 = newVariable(Kind.Int); + append(new CompareAndSwapCompressedOp(casResult, addressValue, expected, newValue, scratchExpected64, scratchNewValue64, scratchExpected32, scratchNewValue32, scratchCasResult32, + getGen().getNarrowOopBase(), getGen().getNarrowOopShift(), getGen().getLogMinObjectAlignment())); + } else { + append(new CompareAndSwapOp(casResult, addressValue, expected, newValue)); + } + Variable nodeResult = newVariable(node.getKind()); + append(new CondMoveOp(HSAILLIRGenerator.mapKindToCompareOp(kind), casResult, expected, nodeResult, Condition.EQ, Constant.INT_1, Constant.INT_0)); + setResult(node, nodeResult); + } + + @Override + protected void emitNode(ValueNode node) { + if (node instanceof CurrentJavaThreadNode) { + throw new GraalInternalError("HSAILHotSpotLIRGenerator cannot handle node: " + node); + } else { + super.emitNode(node); + } + } + + /** + * @return a compressed version of the incoming constant lifted from AMD64HotSpotLIRGenerator + */ + protected static Constant compress(Constant c, CompressEncoding encoding) { + if (c.getKind() == Kind.Long) { + return Constant.forIntegerKind(Kind.Int, (int) (((c.asLong() - encoding.base) >> encoding.shift) & 0xffffffffL), c.getPrimitiveAnnotation()); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,6 +39,7 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.gpu.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; @@ -327,13 +328,13 @@ } @Override - public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { + public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { // Omit the frame of the method: // - has no spill slots or other slots allocated during register allocation // - has no callee-saved registers // - has no incoming arguments passed on the stack // - has no instructions with debug info - FrameMap frameMap = lirGen.frameMap; + FrameMap frameMap = lirGenRes.getFrameMap(); Assembler masm = createAssembler(frameMap); PTXFrameContext frameContext = new PTXFrameContext(); CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult); @@ -342,13 +343,23 @@ } @Override + public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { + return new LIRGenerationResultBase(lir, frameMap); + } + + @Override protected Assembler createAssembler(FrameMap frameMap) { return new PTXMacroAssembler(getTarget(), frameMap.registerConfig); } @Override - public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) { - return new PTXHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir); + public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + return new PTXHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); + } + + @Override + public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + return new PTXHotSpotNodeLIRGenerator(graph, lirGenRes, lirGen); } private static void emitKernelEntry(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod codeCacheOwner) { @@ -367,14 +378,14 @@ asm.emitString(""); // Get the start block - Block startBlock = lir.getControlFlowGraph().getStartBlock(); + AbstractBlock startBlock = lir.getControlFlowGraph().getStartBlock(); // Keep a list of ParameterOp instructions to delete from the // list of instructions in the block. ArrayList deleteOps = new ArrayList<>(); // Emit .param arguments to kernel entry based on ParameterOp // instruction. - for (LIRInstruction op : lir.lir(startBlock)) { + for (LIRInstruction op : lir.getLIRforBlock(startBlock)) { if (op instanceof PTXParameterOp) { op.emitCode(crb); deleteOps.add(op); @@ -383,7 +394,7 @@ // Delete ParameterOp instructions. for (LIRInstruction op : deleteOps) { - lir.lir(startBlock).remove(op); + lir.getLIRforBlock(startBlock).remove(op); } // Start emiting body of the PTX kernel. @@ -398,8 +409,8 @@ RegisterAnalysis registerAnalysis = new RegisterAnalysis(); - for (Block b : lir.codeEmittingOrder()) { - for (LIRInstruction op : lir.lir(b)) { + for (AbstractBlock b : lir.codeEmittingOrder()) { + for (LIRInstruction op : lir.getLIRforBlock(b)) { if (op instanceof LabelOp) { // Don't consider this as a definition } else { diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,36 +23,24 @@ package com.oracle.graal.hotspot.ptx; -import com.oracle.graal.api.code.CallingConvention; -import com.oracle.graal.api.code.StackSlot; -import com.oracle.graal.api.meta.DeoptimizationAction; -import com.oracle.graal.api.meta.DeoptimizationReason; -import com.oracle.graal.api.meta.Value; -import com.oracle.graal.compiler.ptx.PTXLIRGenerator; -import com.oracle.graal.graph.GraalInternalError; -import com.oracle.graal.hotspot.HotSpotLIRGenerator; -import com.oracle.graal.hotspot.HotSpotVMConfig; -import com.oracle.graal.hotspot.meta.HotSpotProviders; -import com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode; -import com.oracle.graal.lir.FrameMap; -import com.oracle.graal.lir.LIR; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.nodes.ValueNode; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.ptx.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; /** * LIR generator specialized for PTX HotSpot. */ public class PTXHotSpotLIRGenerator extends PTXLIRGenerator implements HotSpotLIRGenerator { - protected PTXHotSpotLIRGenerator(StructuredGraph graph, HotSpotProviders providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); + protected PTXHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); assert config.basicLockSize == 8; } - public void emitPrefetchAllocate(ValueNode address, ValueNode distance) { - // nop - } - public void emitTailcall(Value[] args, Value address) { throw GraalInternalError.unimplemented(); } @@ -61,18 +49,6 @@ throw GraalInternalError.unimplemented(); } - public void emitPatchReturnAddress(ValueNode address) { - throw GraalInternalError.unimplemented(); - } - - public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { - throw GraalInternalError.unimplemented(); - } - - public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { - throw GraalInternalError.unimplemented(); - } - public StackSlot getLockSlot(int lockDepth) { throw GraalInternalError.unimplemented(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,58 @@ +/* + * 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.ptx; + +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.ptx.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; + +/** + * LIR generator specialized for PTX HotSpot. + */ +public class PTXHotSpotNodeLIRGenerator extends PTXNodeLIRGenerator implements HotSpotNodeLIRGenerator { + + protected PTXHotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + super(graph, lirGenRes, lirGen); + } + + public void emitPrefetchAllocate(ValueNode address, ValueNode distance) { + // nop + } + + public void emitPatchReturnAddress(ValueNode address) { + throw GraalInternalError.unimplemented(); + } + + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + throw GraalInternalError.unimplemented(); + } + + public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { + throw GraalInternalError.unimplemented(); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotRegisterConfig.java Sun Mar 30 16:08:33 2014 +0200 @@ -74,6 +74,11 @@ } @Override + public boolean areAllAllocatableRegistersCallerSaved() { + throw GraalInternalError.unimplemented(); + } + + @Override public Register getRegisterForRole(int index) { throw GraalInternalError.unimplemented("PTXHotSpotRegisterConfig.getRegisterForRole()"); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java Sun Mar 30 16:08:33 2014 +0200 @@ -235,7 +235,7 @@ for (javaParametersIndex = 0; javaParametersIndex < javaParameters.length; javaParametersIndex++) { ParameterNode javaParameter = javaParameters[javaParametersIndex]; int javaParameterOffset = javaParameterOffsetsInKernelParametersBuffer[javaParametersIndex]; - LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.kind(), javaParameterOffset, getGraph()); + LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.getKind(), javaParameterOffset, getGraph()); append(new WriteNode(buf, javaParameter, location, BarrierType.NONE, false, false)); updateDimArg(method, sig, sigIndex++, args, javaParameter); } @@ -244,13 +244,13 @@ append(new WriteNode(buf, nullWord, location, BarrierType.NONE, false, false)); } - FrameStateBuilder fsb = new FrameStateBuilder(method, getGraph(), true); + HIRFrameStateBuilder fsb = new HIRFrameStateBuilder(method, getGraph(), true); FrameState fs = fsb.create(0); getGraph().start().setStateAfter(fs); ValueNode[] launchArgsArray = args.values().toArray(new ValueNode[args.size()]); ForeignCallNode result = append(new ForeignCallNode(providers.getForeignCalls(), CALL_KERNEL, launchArgsArray)); - result.setDeoptimizationState(fs); + result.setStateAfter(fs); InvokeNode getObjectResult = null; ValueNode returnValue; diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,6 +22,12 @@ */ package com.oracle.graal.hotspot.sparc; +import static com.oracle.graal.api.code.CallingConvention.Type.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.phases.GraalOptions.*; +import static com.oracle.graal.sparc.SPARC.*; +import static java.lang.reflect.Modifier.*; + import java.util.*; import sun.misc.*; @@ -30,26 +36,27 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCAssembler.*; -import com.oracle.graal.compiler.gen.LIRGenerator; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpne; +import com.oracle.graal.asm.sparc.SPARCAssembler.CC; +import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx; +import com.oracle.graal.asm.sparc.SPARCAssembler.Save; +import com.oracle.graal.asm.sparc.SPARCAssembler.Stx; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cmp; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Nop; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.RestoreWindow; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; +import com.oracle.graal.compiler.gen.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; -import com.oracle.graal.hotspot.stubs.Stub; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.sparc.*; import com.oracle.graal.nodes.*; -import static com.oracle.graal.sparc.SPARC.*; -import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; -import static com.oracle.graal.api.code.CallingConvention.Type.*; -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.phases.GraalOptions.*; -import static java.lang.reflect.Modifier.*; - /** * HotSpot SPARC specific backend. */ @@ -72,8 +79,13 @@ } @Override - public LIRGenerator newLIRGenerator(StructuredGraph graph, Object stub, FrameMap frameMap, CallingConvention cc, LIR lir) { - return new SPARCHotSpotLIRGenerator(graph, stub, getProviders(), getRuntime().getConfig(), frameMap, cc, lir); + public LIRGenerator newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) { + return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getConfig(), cc, lirGenRes); + } + + @Override + public NodeLIRGenerator newNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + return new SPARCHotSpotNodeLIRGenerator(graph, lirGenRes, lirGen); } /** @@ -152,10 +164,10 @@ } @Override - public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { - SPARCHotSpotLIRGenerator gen = (SPARCHotSpotLIRGenerator) lirGen; - FrameMap frameMap = gen.frameMap; - assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; + public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { + SPARCHotSpotLIRGenerationResult gen = (SPARCHotSpotLIRGenerationResult) lirGenRes; + FrameMap frameMap = gen.getFrameMap(); + assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; Stub stub = gen.getStub(); Assembler masm = createAssembler(frameMap); @@ -163,7 +175,7 @@ HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, frameContext, compilationResult); crb.setFrameSize(frameMap.frameSize()); - StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot; + StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); if (deoptimizationRescueSlot != null && stub == null) { crb.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot)); } @@ -179,6 +191,11 @@ } @Override + public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMap frameMap, Object stub) { + return new LIRGenerationResultBase(lir, frameMap); + } + + @Override public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; FrameMap frameMap = crb.frameMap; @@ -233,4 +250,5 @@ public NativeFunctionInterface getNativeFunctionInterface() { throw GraalInternalError.unimplemented("No NativeFunctionInterface of SPARC"); } + } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, 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.sparc; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.hotspot.stubs.*; + +public interface SPARCHotSpotLIRGenerationResult extends LIRGenerationResult { + + StackSlot getDeoptimizationRescueSlot(); + + Stub getStub(); + +} diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,11 +23,7 @@ package com.oracle.graal.hotspot.sparc; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.sparc.SPARC.*; - -import java.lang.reflect.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -36,27 +32,22 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.sparc.*; -import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp; import com.oracle.graal.lir.sparc.SPARCMove.LoadOp; import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp; import com.oracle.graal.lir.sparc.SPARCMove.StoreOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator { - private final HotSpotVMConfig config; - private final Object stub; + final HotSpotVMConfig config; - public SPARCHotSpotLIRGenerator(StructuredGraph graph, Object stub, HotSpotProviders providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) { - super(graph, providers, frameMap, cc, lir); + public SPARCHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) { + super(providers, cc, lirGenRes); this.config = config; - this.stub = stub; } @Override @@ -69,28 +60,21 @@ * deoptimization. The return address slot in the callee is overwritten with the address of a * deoptimization stub. */ - StackSlot deoptimizationRescueSlot; - - @SuppressWarnings("hiding") - @Override - protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { - HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long); - return new HotSpotDebugInfoBuilder(nodeOperands, lockStack); - } + private StackSlot deoptimizationRescueSlot; @Override public StackSlot getLockSlot(int lockDepth) { - return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth); + return ((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack().makeLockSlot(lockDepth); } @Override protected boolean needOnlyOopMaps() { // Stubs only need oop maps - return stub != null; + return getStub() != null; } - Stub getStub() { - return (Stub) stub; + public Stub getStub() { + return ((SPARCHotSpotLIRGenerationResult) res).getStub(); } @Override @@ -113,74 +97,17 @@ } @Override - protected void emitReturn(Value input) { + public void emitReturn(Value input) { append(new SPARCHotSpotReturnOp(input, getStub() != null)); } @Override - public void visitSafepointNode(SafepointNode i) { - LIRFrameState info = state(i); - append(new SPARCHotSpotSafepointOp(info, config, this)); - } - - @Override - public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { - Kind kind = x.newValue().kind(); - assert kind == x.expectedValue().kind(); - - Variable address = load(operand(x.object())); - Value offset = operand(x.offset()); - Variable cmpValue = (Variable) loadNonConst(operand(x.expectedValue())); - Variable newValue = load(operand(x.newValue())); - - if (ValueUtil.isConstant(offset)) { - assert !getCodeCache().needsDataPatch(asConstant(offset)); - Variable longAddress = newVariable(Kind.Long); - emitMove(longAddress, address); - address = emitAdd(longAddress, asConstant(offset)); - } else { - if (isLegal(offset)) { - address = emitAdd(address, offset); - } - } - - append(new CompareAndSwapOp(address, cmpValue, newValue)); - - Variable result = newVariable(x.kind()); - emitMove(result, newValue); - setResult(x, result); - } - - @Override public void emitTailcall(Value[] args, Value address) { // append(new AMD64TailcallOp(args, address)); throw GraalInternalError.unimplemented(); } @Override - protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); - if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { - append(new SPARCHotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind)); - } else { - assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special; - HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target(); - assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method."; - Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant(); - append(new SPARCHotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod)); - } - } - - @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - AllocatableValue metaspaceMethod = g5.asValue(); - emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod())); - AllocatableValue targetAddress = g3.asValue(); - emitMove(targetAddress, operand(callTarget.computedAddress())); - append(new SPARCIndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); - } - - @Override public void emitUnwind(Value exception) { ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); @@ -214,26 +141,6 @@ append(new SPARCHotSpotDeoptimizeCallerOp()); } - @Override - public void emitPatchReturnAddress(ValueNode address) { - append(new SPARCHotSpotPatchReturnAddressOp(load(operand(address)))); - } - - @Override - public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { - Variable handler = load(operand(handlerInCallerPc)); - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); - CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); - assert linkageCc.getArgumentCount() == 2; - RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0); - RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1); - emitMove(exceptionFixed, operand(exception)); - emitMove(exceptionPcFixed, operand(exceptionPc)); - Register thread = getProviders().getRegisters().getThreadRegister(); - SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, config.threadIsMethodHandleReturnOffset, thread); - append(op); - } - private static boolean isCompressCandidate(Access access) { return access != null && access.isCompressible(); } @@ -321,8 +228,7 @@ return null; } - public void emitPrefetchAllocate(ValueNode address, ValueNode distance) { - SPARCAddressValue addr = emitAddress(operand(address), 0, loadNonConst(operand(distance)), 1); - append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr)); + public StackSlot getDeoptimizationRescueSlot() { + return deoptimizationRescueSlot; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2013, 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.sparc; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; +import static com.oracle.graal.sparc.SPARC.*; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.sparc.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.sparc.*; +import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; + +public class SPARCHotSpotNodeLIRGenerator extends SPARCNodeLIRGenerator implements HotSpotNodeLIRGenerator { + + public SPARCHotSpotNodeLIRGenerator(StructuredGraph graph, LIRGenerationResult lirGenRes, LIRGenerator lirGen) { + super(graph, lirGenRes, lirGen); + } + + @Override + protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { + HotSpotLockStack lockStack = new HotSpotLockStack(res.getFrameMap(), Kind.Long); + return new HotSpotDebugInfoBuilder(nodeOperands, lockStack); + } + + private SPARCHotSpotLIRGenerator getGen() { + return (SPARCHotSpotLIRGenerator) gen; + } + + @Override + public void visitSafepointNode(SafepointNode i) { + LIRFrameState info = gen.state(i); + append(new SPARCHotSpotSafepointOp(info, getGen().config, gen)); + } + + @Override + public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { + Kind kind = x.newValue().getKind(); + assert kind == x.expectedValue().getKind(); + + Variable address = gen.load(operand(x.object())); + Value offset = operand(x.offset()); + Variable cmpValue = (Variable) gen.loadNonConst(operand(x.expectedValue())); + Variable newValue = gen.load(operand(x.newValue())); + + if (ValueUtil.isConstant(offset)) { + assert !gen.getCodeCache().needsDataPatch(asConstant(offset)); + Variable longAddress = newVariable(Kind.Long); + gen.emitMove(longAddress, address); + address = getGen().emitAdd(longAddress, asConstant(offset)); + } else { + if (isLegal(offset)) { + address = getGen().emitAdd(address, offset); + } + } + + append(new CompareAndSwapOp(address, cmpValue, newValue)); + + Variable result = newVariable(x.getKind()); + gen.emitMove(result, newValue); + setResult(x, result); + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); + if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { + append(new SPARCHotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind)); + } else { + assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special; + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target(); + assert !Modifier.isAbstract(resolvedMethod.getModifiers()) : "Cannot make direct call to abstract method."; + Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant(); + append(new SPARCHotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod)); + } + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + AllocatableValue metaspaceMethod = g5.asValue(); + gen.emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod())); + AllocatableValue targetAddress = g3.asValue(); + gen.emitMove(targetAddress, operand(callTarget.computedAddress())); + append(new SPARCIndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); + } + + @Override + public void emitPatchReturnAddress(ValueNode address) { + append(new SPARCHotSpotPatchReturnAddressOp(gen.load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + Variable handler = gen.load(operand(handlerInCallerPc)); + ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); + assert linkageCc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1); + gen.emitMove(exceptionFixed, operand(exception)); + gen.emitMove(exceptionPcFixed, operand(exceptionPc)); + Register thread = getGen().getProviders().getRegisters().getThreadRegister(); + SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset, + thread); + append(op); + } + + public void emitPrefetchAllocate(ValueNode address, ValueNode distance) { + SPARCAddressValue addr = getGen().emitAddress(operand(address), 0, getGen().loadNonConst(operand(distance)), 1); + append(new SPARCPrefetchOp(addr, getGen().config.allocatePrefetchInstr)); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Sun Mar 30 16:08:33 2014 +0200 @@ -144,6 +144,11 @@ } @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return false; + } + + @Override public Register getRegisterForRole(int index) { throw new UnsupportedOperationException(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -67,7 +67,7 @@ public void testStaticFinalObjectAOT() { StructuredGraph result = compile("getStaticFinalObject", true); assertEquals(1, getConstantNodes(result).count()); - assertEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().kind()); + assertEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().getKind()); assertEquals(2, result.getNodes(FloatingReadNode.class).count()); assertEquals(0, result.getNodes().filter(ReadNode.class).count()); } @@ -76,7 +76,7 @@ public void testStaticFinalObject() { StructuredGraph result = compile("getStaticFinalObject", false); assertEquals(1, getConstantNodes(result).count()); - assertEquals(Kind.Object, getConstantNodes(result).first().kind()); + assertEquals(Kind.Object, getConstantNodes(result).first().getKind()); assertEquals(0, result.getNodes(FloatingReadNode.class).count()); assertEquals(0, result.getNodes().filter(ReadNode.class).count()); } @@ -121,7 +121,7 @@ StructuredGraph result = compile("getPrimitiveClassObject", true); NodeIterable filter = getConstantNodes(result); assertEquals(1, filter.count()); - assertEquals(getCodeCache().getTarget().wordKind, filter.first().kind()); + assertEquals(getCodeCache().getTarget().wordKind, filter.first().getKind()); assertEquals(2, result.getNodes(FloatingReadNode.class).count()); assertEquals(0, result.getNodes().filter(ReadNode.class).count()); @@ -181,7 +181,7 @@ assertEquals(1, result.getNodes(PiNode.class).count()); assertEquals(1, getConstantNodes(result).count()); ConstantNode constant = getConstantNodes(result).first(); - assertEquals(Kind.Long, constant.kind()); + assertEquals(Kind.Long, constant.getKind()); assertEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant()); } @@ -192,7 +192,7 @@ assertEquals(0, result.getNodes(PiNode.class).count()); assertEquals(1, getConstantNodes(result).count()); ConstantNode constant = getConstantNodes(result).first(); - assertEquals(Kind.Object, constant.kind()); + assertEquals(Kind.Object, constant.getKind()); assertEquals(Boolean.TRUE, constant.asConstant().asObject()); } diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Sun Mar 30 16:08:33 2014 +0200 @@ -31,6 +31,7 @@ import static com.oracle.graal.phases.common.InliningUtil.*; import java.io.*; +import java.lang.management.*; import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; @@ -39,19 +40,23 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.CompilerThreadFactory.CompilerThread; +import com.oracle.graal.baseline.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.debug.internal.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.java.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class CompilationTask implements Runnable, Comparable { private static final long TIMESTAMP_START = System.currentTimeMillis(); @@ -106,6 +111,12 @@ private boolean blocking; + /** + * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the + * current compiler thread, e.g. total allocated bytes. + */ + private final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); + public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) { this.backend = backend; this.method = method; @@ -128,6 +139,7 @@ return entryBCI; } + @SuppressFBWarnings(value = "NN_NAKED_NOTIFY") public void run() { withinEnqueue.set(Boolean.FALSE); try { @@ -208,9 +220,11 @@ */ HotSpotVMConfig config = backend.getRuntime().getConfig(); + final long threadId = Thread.currentThread().getId(); long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue(); long previousCompilationTime = CompilationTime.getCurrentValue(); HotSpotInstalledCode installedCode = null; + try (TimerCloseable a = CompilationTime.start()) { if (!tryToChangeStatus(CompilationStatus.Queued, CompilationStatus.Running)) { return; @@ -235,36 +249,45 @@ CompilationResult result = null; TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); - long start = System.currentTimeMillis(); + final long start = System.currentTimeMillis(); + final long allocatedBytesBefore = threadMXBean.getThreadAllocatedBytes(threadId); + try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) { - Map graphCache = null; - if (GraalOptions.CacheGraphs.getValue()) { - graphCache = new HashMap<>(); - } - HotSpotProviders providers = backend.getProviders(); - Replacements replacements = providers.getReplacements(); - graph = replacements.getMethodSubstitution(method); - if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) { - graph = new StructuredGraph(method, entryBCI); + if (UseBaselineCompiler.getValue() == true) { + HotSpotProviders providers = backend.getProviders(); + BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess()); + result = baselineCompiler.generate(method, -1, backend, new CompilationResult(), method, CompilationResultBuilderFactory.Default); } else { - // Compiling method substitution - must clone the graph - graph = graph.copy(); + Map graphCache = null; + if (GraalOptions.CacheGraphs.getValue()) { + graphCache = new HashMap<>(); + } + + HotSpotProviders providers = backend.getProviders(); + Replacements replacements = providers.getReplacements(); + graph = replacements.getMethodSubstitution(method); + if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) { + graph = new StructuredGraph(method, entryBCI); + } else { + // Compiling method substitution - must clone the graph + graph = graph.copy(); + } + InlinedBytecodes.add(method.getCodeSize()); + CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); + if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) { + // for OSR, only a pointer is passed to the method. + JavaType[] parameterTypes = new JavaType[]{providers.getMetaAccess().lookupJavaType(long.class)}; + CallingConvention tmp = providers.getCodeCache().getRegisterConfig().getCallingConvention(JavaCallee, providers.getMetaAccess().lookupJavaType(void.class), parameterTypes, + backend.getTarget(), false); + cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0)); + } + Suites suites = getSuites(providers); + ProfilingInfo profilingInfo = getProfilingInfo(); + OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo); + result = compileGraph(graph, null, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo, + method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default); } - InlinedBytecodes.add(method.getCodeSize()); - CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); - if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) { - // for OSR, only a pointer is passed to the method. - JavaType[] parameterTypes = new JavaType[]{providers.getMetaAccess().lookupJavaType(long.class)}; - CallingConvention tmp = providers.getCodeCache().getRegisterConfig().getCallingConvention(JavaCallee, providers.getMetaAccess().lookupJavaType(void.class), parameterTypes, - backend.getTarget(), false); - cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0)); - } - Suites suites = getSuites(providers); - ProfilingInfo profilingInfo = getProfilingInfo(); - OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo); - result = compileGraph(graph, null, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo, - method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default); result.setId(getId()); result.setEntryBCI(entryBCI); } catch (Throwable e) { @@ -272,10 +295,18 @@ } finally { filter.remove(); final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed(); - if (printAfterCompilation) { - TTY.println(getMethodDescription() + String.format(" | %4dms %5dB", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1))); - } else if (printCompilation) { - TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1))); + + if (printAfterCompilation || printCompilation) { + final long stop = System.currentTimeMillis(); + final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1; + final long allocatedBytesAfter = threadMXBean.getThreadAllocatedBytes(threadId); + final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; + + if (printAfterCompilation) { + TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes)); + } else if (printCompilation) { + TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB %5dkB", id, "", "", "", stop - start, targetCodeSize, allocatedBytes)); + } } } diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Sun Mar 30 16:08:33 2014 +0200 @@ -113,8 +113,8 @@ return value; } }; - for (Block block : lir.codeEmittingOrder()) { - for (LIRInstruction op : lir.lir(block)) { + for (AbstractBlock block : lir.codeEmittingOrder()) { + for (LIRInstruction op : lir.getLIRforBlock(block)) { if (op instanceof LabelOp) { // Don't consider this as a definition } else { diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,13 +26,11 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; /** * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition - * to abstract methods from {@link LIRGenerator} and {@link LIRGeneratorTool}. + * to abstract methods from {@link LIRGenerator} and {@link NodeLIRGeneratorTool}. */ public interface HotSpotLIRGenerator { @@ -46,14 +44,6 @@ void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason); - void emitPatchReturnAddress(ValueNode address); - - void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc); - - void emitPrefetchAllocate(ValueNode address, ValueNode distance); - - void visitDirectCompareAndSwap(DirectCompareAndSwapNode x); - /** * Gets a stack slot for a lock at a given lock nesting depth. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot; + +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition + * to abstract methods from {@link LIRGenerator} and {@link NodeLIRGeneratorTool}. + */ +public interface HotSpotNodeLIRGenerator { + + void emitPatchReturnAddress(ValueNode address); + + void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc); + + void emitPrefetchAllocate(ValueNode address, ValueNode distance); + + void visitDirectCompareAndSwap(DirectCompareAndSwapNode x); + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java Sun Mar 30 16:08:33 2014 +0200 @@ -76,6 +76,18 @@ } } + public PlatformKind getRegister(int idx) { + int refMapIndex = idx * 2; + if (registerRefMap.get(refMapIndex)) { + if (registerRefMap.get(refMapIndex + 1)) { + return NarrowOopStamp.NarrowOop; + } else { + return Kind.Object; + } + } + return null; + } + public void setStackSlot(int offset, PlatformKind kind) { int idx = offset / frameSlotSize; if (kind == Kind.Object) { diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Sun Mar 30 16:08:33 2014 +0200 @@ -1005,6 +1005,24 @@ @HotSpotVMField(name = "ThreadShadow::_pending_failed_speculation", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingFailedSpeculationOffset; /** + * Offsets of Hsail deoptimization fields (defined in gpu_hsail.hpp). Used to propagate + * exceptions from Hsail back to C++ runtime. + */ + @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[0]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset0; + @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[1]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset1; + @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_occurred", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptOffset; + @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_never_ran_array", type = "jboolean *", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNeverRanArrayOffset; + @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_next_index", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptNextIndexOffset; + + @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_workitemid", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationWorkItem; + @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_actionAndReason", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationReason; + @HotSpotVMField(name = "Hsail::HSAILKernelDeoptimization::_first_frame", type = "HSAILFrame", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptimizationFrame; + + @HotSpotVMField(name = "HSAILFrame::_pc_offset", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFramePcOffset; + @HotSpotVMField(name = "HSAILFrame::_num_s_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumSRegOffset; + @HotSpotVMField(name = "HSAILFrame::_save_area[0]", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameSaveAreaOffset; + + /** * Mark word right shift to get identity hash code. */ @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public int identityHashCodeShift; @@ -1022,8 +1040,15 @@ @HotSpotVMField(name = "Method::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int methodAccessFlagsOffset; @HotSpotVMField(name = "Method::_constMethod", type = "ConstMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodConstMethodOffset; @HotSpotVMField(name = "Method::_intrinsic_id", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodIntrinsicIdOffset; + @HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset; @HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset; + @HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite; + @HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive; + @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline; + @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline; + @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden; + @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch; @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes; @@ -1276,6 +1301,7 @@ @HotSpotVMConstant(name = "DataLayout::call_type_data_tag") @Stable public int dataLayoutCallTypeDataTag; @HotSpotVMConstant(name = "DataLayout::virtual_call_type_data_tag") @Stable public int dataLayoutVirtualCallTypeDataTag; @HotSpotVMConstant(name = "DataLayout::parameters_type_data_tag") @Stable public int dataLayoutParametersTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::speculative_trap_data_tag") @Stable public int dataLayoutSpeculativeTrapDataTag; @HotSpotVMFlag(name = "BciProfileWidth") @Stable public int bciProfileWidth; @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Sun Mar 30 16:08:33 2014 +0200 @@ -99,12 +99,12 @@ long getKlassImplementor(long metaspaceKlass); /** - * Initializes a {@link HotSpotResolvedJavaMethod} object from a metaspace Method object. + * Determines if a given metaspace method is ignored by security stack walks. * * @param metaspaceMethod the metaspace Method object - * @param method address of a metaspace Method object + * @return true if the method is ignored */ - void initializeMethod(long metaspaceMethod, HotSpotResolvedJavaMethod method); + boolean methodIsIgnoredBySecurityStackWalk(long metaspaceMethod); /** * Converts a name to a metaspace klass. diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Sun Mar 30 16:08:33 2014 +0200 @@ -104,8 +104,7 @@ @Override public native boolean hasFinalizableSubclass(long metaspaceKlass); - @Override - public native void initializeMethod(long metaspaceMethod, HotSpotResolvedJavaMethod method); + public native boolean methodIsIgnoredBySecurityStackWalk(long metaspaceMethod); @Override public native long getClassInitializer(long metaspaceKlass); diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,7 +33,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.CompilerThreadFactory.CompilerThread; import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/OopData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/OopData.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/data/OopData.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.type.*; /** @@ -39,6 +40,7 @@ public OopData(int alignment, Object object, boolean compressed) { super(alignment); + assert !compressed || HotSpotGraalRuntime.runtime().getConfig().useCompressedOops; this.object = object; this.compressed = compressed; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot.debug; import java.io.*; -import java.text.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -36,8 +35,8 @@ import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; @@ -45,22 +44,24 @@ import com.oracle.graal.options.*; import com.oracle.graal.replacements.nodes.*; +import edu.umd.cs.findbugs.annotations.*; + /** * This class contains infrastructure to maintain counters based on {@link DynamicCounterNode}s. The * infrastructure is enabled by specifying either the GenericDynamicCounters or * BenchmarkDynamicCounters option.
- * + * * The counters are kept in a special area allocated for each native JavaThread object, and the * number of counters is configured using {@code -XX:GraalCounterSize=value}. * {@code -XX:+/-GraalCountersExcludeCompiler} configures whether to exclude compiler threads * (defaults to true). - * + * * The subsystems that use the logging need to have their own options to turn on the counters, and * insert DynamicCounterNodes when they're enabled. - * + * * Counters will be displayed as a rate (per second) if their group name starts with "~", otherwise * they will be displayed as a total number. - * + * *

Example

In order to create statistics about allocations within the DaCapo pmd benchmark * the following steps are necessary: *
    @@ -83,6 +84,8 @@ //@formatter:off @Option(help = "Turn on the benchmark counters, and displays the results on VM shutdown") private static final OptionValue GenericDynamicCounters = new OptionValue<>(false); + @Option(help = "Turn on the benchmark counters, and displays the results every n milliseconds") + private static final OptionValue TimedDynamicCounters = new OptionValue<>(-1); @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" + "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" + @@ -103,13 +106,15 @@ public static long[] delta; public static final ArrayList staticCounters = new ArrayList<>(); + @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block") public static int getIndex(DynamicCounterNode counter) { if (!enabled) { throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName()); } String name = counter.getName(); String group = counter.getGroup(); - name = counter.isWithContext() ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name + "#" + group; + name = counter.isWithContext() && counter.graph().method() != null ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name + + "#" + group; Integer index = indexes.get(name); if (index == null) { synchronized (BenchmarkCounters.class) { @@ -129,15 +134,15 @@ return index; } - public static synchronized void dump(PrintStream out, double seconds, long[] counters) { + public static synchronized void dump(PrintStream out, double seconds, long[] counters, int maxRows) { if (!groups.isEmpty()) { out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======"); for (String group : new TreeSet<>(groups)) { if (group != null) { if (DUMP_STATIC) { - dumpCounters(out, seconds, counters, true, group); + dumpCounters(out, seconds, counters, true, group, maxRows); } - dumpCounters(out, seconds, counters, false, group); + dumpCounters(out, seconds, counters, false, group, maxRows); } } out.println("============================"); @@ -150,9 +155,10 @@ delta = counters; } - private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group) { + private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group, int maxRows) { TreeMap sorted = new TreeMap<>(); + // collect the numbers long[] array; if (staticCounter) { array = new long[indexes.size()]; @@ -165,6 +171,7 @@ array[i] -= delta[i]; } } + // sort the counters by putting them into a sorted map long sum = 0; for (Map.Entry entry : indexes.entrySet()) { int index = entry.getValue(); @@ -175,41 +182,51 @@ } if (sum > 0) { - NumberFormat format = NumberFormat.getInstance(Locale.US); long cutoff = sorted.size() < 10 ? 1 : Math.max(1, sum / 100); + int cnt = sorted.size(); + + // remove everything below cutoff and keep at most maxRows + Iterator> iter = sorted.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + long counter = entry.getKey() / array.length; + if (counter < cutoff || cnt > maxRows) { + iter.remove(); + } + cnt--; + } + if (staticCounter) { out.println("=========== " + group + " (static counters):"); for (Map.Entry entry : sorted.entrySet()) { long counter = entry.getKey() / array.length; - if (counter >= cutoff) { - out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); - } + out.format(Locale.US, "%,19d %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); } - out.println(sum + ": total"); + out.format(Locale.US, "%,19d total\n", sum); } else { if (group.startsWith("~")) { out.println("=========== " + group + " (dynamic counters), time = " + seconds + " s:"); for (Map.Entry entry : sorted.entrySet()) { long counter = entry.getKey() / array.length; - if (counter >= cutoff) { - out.println(format.format((long) (counter / seconds)) + "/s \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); - } + out.format(Locale.US, "%,19d/s %3d%% %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue()); } - out.println(format.format((long) (sum / seconds)) + "/s: total"); + out.format(Locale.US, "%,19d/s total\n", (long) (sum / seconds)); } else { out.println("=========== " + group + " (dynamic counters):"); for (Map.Entry entry : sorted.entrySet()) { long counter = entry.getKey() / array.length; - if (counter >= cutoff) { - out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); - } + out.format(Locale.US, "%,19d %3d%% %s\n", counter, percentage(counter, sum), entry.getValue()); } - out.println(format.format(sum) + ": total"); + out.format(Locale.US, "%,19d total\n", sum); } } } } + private static long percentage(long counter, long sum) { + return (counter * 200 + 1) / sum / 2; + } + public abstract static class CallbackOutputStream extends OutputStream { protected final PrintStream delegate; @@ -282,7 +299,7 @@ case 2: if (waitingForEnd) { waitingForEnd = false; - BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters()); + BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters(), 100); } break; } @@ -309,20 +326,43 @@ if (Options.GenericDynamicCounters.getValue()) { enabled = true; } - if (Options.GenericDynamicCounters.getValue() || Options.BenchmarkDynamicCounters.getValue() != null) { + if (Options.TimedDynamicCounters.getValue() > 0) { + Thread thread = new Thread() { + long lastTime = System.nanoTime(); + PrintStream out = System.out; + + @Override + public void run() { + while (true) { + try { + Thread.sleep(Options.TimedDynamicCounters.getValue()); + } catch (InterruptedException e) { + } + long time = System.nanoTime(); + dump(out, (time - lastTime) / 1000000000d, compilerToVM.collectCounters(), 10); + lastTime = time; + } + } + }; + thread.setDaemon(true); + thread.setPriority(Thread.MAX_PRIORITY); + thread.start(); + enabled = true; + } + if (enabled) { clear(compilerToVM.collectCounters()); } } public static void shutdown(CompilerToVM compilerToVM, long compilerStartTime) { if (Options.GenericDynamicCounters.getValue()) { - dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters()); + dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters(), 100); } } public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) { StructuredGraph graph = counter.graph(); - if (excludedClassPrefix == null || !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { + if (excludedClassPrefix == null || (counter.graph().method() != null && !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix))) { ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false)); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.hotspot.logging; +import java.io.*; import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; @@ -94,16 +95,15 @@ } } - // CheckStyle: stop system..print check protected void print() { long sum = 0; + PrintStream out = System.out; for (Map.Entry entry : calls.entrySet()) { Method method = entry.getKey(); long count = entry.getValue().get(); sum += count; - System.out.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count); + out.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count); } - System.out.println(delegate.getClass().getSimpleName() + " calls: " + sum); + out.println(delegate.getClass().getSimpleName() + " calls: " + sum); } - // CheckStyle: resume system..print check } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Sun Mar 30 16:08:33 2014 +0200 @@ -259,9 +259,9 @@ StructuredGraph graph = loadField.graph(); HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object(); - assert loadField.kind() != Kind.Illegal; + assert loadField.getKind() != Kind.Illegal; BarrierType barrierType = getFieldLoadBarrierType(field); - ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); + ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.getKind() == Kind.Object))); graph.replaceFixedWithFixed(loadField, memoryRead); memoryRead.setGuard(createNullCheck(object, memoryRead, tool)); @@ -296,9 +296,9 @@ private static void lowerCompareAndSwapNode(CompareAndSwapNode cas) { // Separate out GC barrier semantics StructuredGraph graph = cas.graph(); - LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); + LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().getKind(), cas.displacement(), cas.offset(), graph, 1); LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas), - cas.expected().kind() == Kind.Object)); + cas.expected().getKind() == Kind.Object)); atomicNode.setStateAfter(cas.stateAfter()); graph.replaceFixedWithFixed(cas, atomicNode); } @@ -372,7 +372,7 @@ graph.replaceFixedWithFixed(load, valueAnchorNode); graph.addAfterFixed(valueAnchorNode, memoryRead); } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) { - assert load.kind() != Kind.Illegal; + assert load.getKind() != Kind.Illegal; boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); if (addReadBarrier(load)) { unsafeLoadSnippets.lower(load, tool); @@ -392,7 +392,7 @@ LocationNode location = createLocation(store); ValueNode object = store.object(); BarrierType barrierType = getUnsafeStoreBarrierType(store); - WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object)); + WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().getKind() == Kind.Object)); write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); } @@ -401,7 +401,7 @@ StructuredGraph graph = loadHub.graph(); if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) { Kind wordKind = runtime.getTarget().wordKind; - assert loadHub.kind() == wordKind; + assert loadHub.getKind() == wordKind; ValueNode object = loadHub.object(); GuardingNode guard = loadHub.getGuard(); FloatingReadNode hub = createReadHub(graph, wordKind, object, guard); @@ -447,7 +447,7 @@ omittedValues.set(valuePos); } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { // Constant.illegal is always the defaultForKind, so it is skipped - Kind valueKind = value.kind(); + Kind valueKind = value.getKind(); Kind entryKind = virtual.entryKind(i); // Truffle requires some leniency in terms of what can be put where: @@ -483,7 +483,7 @@ assert value instanceof VirtualObjectNode; ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { - assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object; + assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object; WriteNode write; if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; @@ -520,9 +520,9 @@ // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) int localsOffset = (graph.method().getMaxLocals() - 1) * 8; for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) { - int size = FrameStateBuilder.stackSlots(osrLocal.kind()); + int size = HIRFrameStateBuilder.stackSlots(osrLocal.getKind()); int offset = localsOffset - (osrLocal.index() + size - 1) * 8; - IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1); + IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.getKind(), offset, ConstantNode.forLong(0, graph), graph, 1); ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false)); osrLocal.replaceAndDelete(load); graph.addBeforeFixed(migrationEnd, load); @@ -606,7 +606,7 @@ } private static boolean addReadBarrier(UnsafeLoadNode load) { - if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object && + if (useG1GC() && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object && !ObjectStamp.isObjectAlwaysNull(load.object())) { ResolvedJavaType type = ObjectStamp.typeOrNull(load.object()); if (type != null && !type.isArray()) { @@ -669,7 +669,7 @@ private static BarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) { BarrierType barrierType = BarrierType.NONE; - if (store.value().kind() == Kind.Object) { + if (store.value().getKind() == Kind.Object) { ResolvedJavaType type = ObjectStamp.typeOrNull(store.object()); if (type != null && !type.isArray()) { barrierType = BarrierType.IMPRECISE; @@ -682,7 +682,7 @@ private static BarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) { BarrierType barrierType = BarrierType.NONE; - if (cas.expected().kind() == Kind.Object) { + if (cas.expected().getKind() == Kind.Object) { ResolvedJavaType type = ObjectStamp.typeOrNull(cas.object()); if (type != null && !type.isArray()) { barrierType = BarrierType.IMPRECISE; @@ -763,6 +763,15 @@ arrayLength = readArrayLength; } + if (arrayLength.isConstant() && n.index().isConstant()) { + int l = arrayLength.asConstant().asInt(); + int i = n.index().asConstant().asInt(); + if (i >= 0 && i < l) { + // unneeded range check + return null; + } + } + return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,11 +23,15 @@ package com.oracle.graal.hotspot.meta; import static com.oracle.graal.api.meta.MetaUtil.*; +import static com.oracle.graal.debug.Debug.*; +import static java.util.FormattableFlags.*; + +import java.util.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; -public abstract class HotSpotMethod extends CompilerObject implements JavaMethod { +public abstract class HotSpotMethod extends CompilerObject implements JavaMethod, Formattable { private static final long serialVersionUID = 7167491397941960839L; protected String name; @@ -54,4 +58,9 @@ String fmt = String.format("HotSpotMethod<%%%c.%%n(%%p)%s>", h, suffix); return format(fmt, this); } + + public void formatTo(Formatter formatter, int flags, int width, int precision) { + String base = (flags & ALTERNATE) == ALTERNATE ? getName() : toString(); + formatter.format(applyFormattingFlagsAndWidth(base, flags & ~ALTERNATE, width)); + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.HotSpotMethodDataAccessor.Tag; /** * Access to a HotSpot MethodData structure (defined in methodData.hpp). @@ -57,7 +58,11 @@ new RetData(), new BranchData(), new MultiBranchData(), - new ArgInfoData() + new ArgInfoData(), + null, // call_type_data_tag + null, // virtual_call_type_data_tag + null, // parameters_type_data_tag + null // speculative_trap_data_tag }; // @formatter:on @@ -146,9 +151,10 @@ private HotSpotMethodDataAccessor getData(int position) { assert position >= 0 : "out of bounds"; - int tag = AbstractMethodData.readTag(this, position); - assert tag >= 0 && tag < PROFILE_DATA_ACCESSORS.length : "illegal tag " + tag; - return PROFILE_DATA_ACCESSORS[tag]; + final Tag tag = AbstractMethodData.readTag(this, position); + HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag.getValue()]; + assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; + return accessor; } private int readUnsignedByte(int position, int offsetInBytes) { @@ -258,20 +264,21 @@ */ private static final int EXCEPTIONS_MASK = 0x2; - private final int tag; + private final Tag tag; private final int staticSize; - protected AbstractMethodData(int tag, int staticSize) { + protected AbstractMethodData(Tag tag, int staticSize) { this.tag = tag; this.staticSize = staticSize; } - public int getTag() { + public Tag getTag() { return tag; } - public static int readTag(HotSpotMethodData data, int position) { - return data.readUnsignedByte(position, config.dataLayoutTagOffset); + public static Tag readTag(HotSpotMethodData data, int position) { + final int tag = data.readUnsignedByte(position, config.dataLayoutTagOffset); + return Tag.getEnum(tag); } @Override @@ -337,7 +344,7 @@ private final TriState exceptionSeen; protected NoMethodData(TriState exceptionSeen) { - super(runtime().getConfig().dataLayoutNoTag, NO_DATA_SIZE); + super(Tag.No, NO_DATA_SIZE); this.exceptionSeen = exceptionSeen; } @@ -363,10 +370,10 @@ private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01; private BitData() { - super(runtime().getConfig().dataLayoutBitDataTag, BIT_DATA_SIZE); + super(Tag.BitData, BIT_DATA_SIZE); } - protected BitData(int tag, int staticSize) { + protected BitData(Tag tag, int staticSize) { super(tag, staticSize); } @@ -387,10 +394,10 @@ private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0); public CounterData() { - super(runtime().getConfig().dataLayoutCounterDataTag, COUNTER_DATA_SIZE); + super(Tag.CounterData, COUNTER_DATA_SIZE); } - protected CounterData(int tag, int staticSize) { + protected CounterData(Tag tag, int staticSize) { super(tag, staticSize); } @@ -416,10 +423,10 @@ protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1); public JumpData() { - super(runtime().getConfig().dataLayoutJumpDataTag, JUMP_DATA_SIZE); + super(Tag.JumpData, JUMP_DATA_SIZE); } - protected JumpData(int tag, int staticSize) { + protected JumpData(Tag tag, int staticSize) { super(tag, staticSize); } @@ -465,7 +472,7 @@ protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2); protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3); - protected AbstractTypeData(int tag, int staticSize) { + protected AbstractTypeData(Tag tag, int staticSize) { super(tag, staticSize); } @@ -548,7 +555,7 @@ private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; public TypeCheckData() { - super(runtime().getConfig().dataLayoutReceiverTypeDataTag, TYPE_CHECK_DATA_SIZE); + super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE); } @Override @@ -569,12 +576,12 @@ private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; public VirtualCallData() { - super(runtime().getConfig().dataLayoutVirtualCallDataTag, VIRTUAL_CALL_DATA_SIZE); + super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE); } @Override public int getExecutionCount(HotSpotMethodData data, int position) { - int typeProfileWidth = config.typeProfileWidth; + final int typeProfileWidth = config.typeProfileWidth; long total = 0; for (int i = 0; i < typeProfileWidth; i++) { @@ -670,7 +677,7 @@ private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; public RetData() { - super(runtime().getConfig().dataLayoutRetDataTag, RET_DATA_SIZE); + super(Tag.RetData, RET_DATA_SIZE); } } @@ -680,7 +687,7 @@ private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2); public BranchData() { - super(runtime().getConfig().dataLayoutBranchDataTag, BRANCH_DATA_SIZE); + super(Tag.BranchData, BRANCH_DATA_SIZE); } @Override @@ -712,7 +719,7 @@ private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0); protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1); - public ArrayData(int tag, int staticSize) { + public ArrayData(Tag tag, int staticSize) { super(tag, staticSize); } @@ -740,7 +747,7 @@ private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); public MultiBranchData() { - super(runtime().getConfig().dataLayoutMultiBranchDataTag, MULTI_BRANCH_DATA_SIZE); + super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE); } @Override @@ -822,7 +829,7 @@ private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); public ArgInfoData() { - super(runtime().getConfig().dataLayoutArgInfoDataTag, ARG_INFO_DATA_SIZE); + super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,8 +22,12 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; /** * Interface for accessor objects that encapsulate the logic for accessing the different kinds of @@ -33,11 +37,54 @@ public interface HotSpotMethodDataAccessor { /** - * Returns the tag stored in the LayoutData header. + * {@code DataLayout} tag values. + */ + enum Tag { + No(config().dataLayoutNoTag), + BitData(config().dataLayoutBitDataTag), + CounterData(config().dataLayoutCounterDataTag), + JumpData(config().dataLayoutJumpDataTag), + ReceiverTypeData(config().dataLayoutReceiverTypeDataTag), + VirtualCallData(config().dataLayoutVirtualCallDataTag), + RetData(config().dataLayoutRetDataTag), + BranchData(config().dataLayoutBranchDataTag), + MultiBranchData(config().dataLayoutMultiBranchDataTag), + ArgInfoData(config().dataLayoutArgInfoDataTag), + CallTypeData(config().dataLayoutCallTypeDataTag), + VirtualCallTypeData(config().dataLayoutVirtualCallTypeDataTag), + ParametersTypeData(config().dataLayoutParametersTypeDataTag), + SpeculativeTrapData(config().dataLayoutSpeculativeTrapDataTag); + + private final int value; + + private Tag(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + private static HotSpotVMConfig config() { + return runtime().getConfig(); + } + + public static Tag getEnum(int value) { + for (Tag e : values()) { + if (e.value == value) { + return e; + } + } + throw GraalInternalError.shouldNotReachHere("unknown enum value " + value); + } + } + + /** + * Returns the {@link Tag} stored in the LayoutData header. * - * @return An integer >= 0 or -1 if not supported. + * @return tag stored in the LayoutData header */ - int getTag(); + Tag getTag(); /** * Returns the BCI stored in the LayoutData header. diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Sun Mar 30 16:08:33 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -53,10 +53,6 @@ private final HotSpotResolvedObjectType holder; private final HotSpotConstantPool constantPool; private final HotSpotSignature signature; - private boolean callerSensitive; - private boolean forceInline; - private boolean dontInline; - private boolean ignoredBySecurityStackWalk; private HotSpotMethodData methodData; private byte[] code; private SpeculationLog speculationLog; @@ -109,8 +105,6 @@ final int signatureIndex = unsafe.getChar(constMethod + config.constMethodSignatureIndexOffset); this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); - - runtime().getCompilerToVM().initializeMethod(metaspaceMethod, this); } /** @@ -139,11 +133,20 @@ } /** + * Returns this method's flags ({@code Method::_flags}). + * + * @return flags of this method + */ + private int getFlags() { + return unsafe.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset); + } + + /** * Returns this method's constant method flags ({@code ConstMethod::_flags}). * * @return flags of this method's ConstMethod */ - private long getConstMethodFlags() { + private int getConstMethodFlags() { return unsafe.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset); } @@ -169,8 +172,7 @@ * modifiers as well as the HotSpot internal modifiers. */ public int getAllModifiers() { - HotSpotVMConfig config = runtime().getConfig(); - return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset); + return unsafe.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset); } @Override @@ -245,19 +247,36 @@ } /** - * Returns true if this method has a CallerSensitive annotation. + * Returns true if this method has a {@code CallerSensitive} annotation. * * @return true if CallerSensitive annotation present, false otherwise */ public boolean isCallerSensitive() { - return callerSensitive; + return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0; + } + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + public boolean isForceInline() { + return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0; + } + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + public boolean isDontInline() { + return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0; } /** * Manually adds a DontInline annotation to this method. */ public void setNotInlineable() { - dontInline = true; runtime().getCompilerToVM().doNotInlineOrCompile(metaspaceMethod); } @@ -268,7 +287,7 @@ * @return true if special method ignored by security stack walks, false otherwise */ public boolean ignoredBySecurityStackWalk() { - return ignoredBySecurityStackWalk; + return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(metaspaceMethod); } public boolean hasBalancedMonitors() { @@ -502,7 +521,7 @@ @Override public boolean canBeInlined() { - if (dontInline) { + if (isDontInline()) { return false; } return runtime().getCompilerToVM().canInlineMethod(metaspaceMethod); @@ -510,7 +529,7 @@ @Override public boolean shouldBeInlined() { - if (forceInline) { + if (isForceInline()) { return true; } return runtime().getCompilerToVM().shouldInlineMethod(metaspaceMethod); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java Sun Mar 30 16:08:33 2014 +0200 @@ -122,7 +122,7 @@ public int getParameterSlots(boolean withReceiver) { int argSlots = 0; for (int i = 0; i < getParameterCount(false); i++) { - argSlots += FrameStateBuilder.stackSlots(getParameterKind(i)); + argSlots += HIRFrameStateBuilder.stackSlots(getParameterKind(i)); } return argSlots + (withReceiver ? 1 : 0); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java Sun Mar 30 16:08:33 2014 +0200 @@ -79,12 +79,12 @@ // box result BoxNode boxedResult; - if (callNode.kind() != Kind.Void) { - if (callNode.kind() == Kind.Object) { + if (callNode.getKind() != Kind.Void) { + if (callNode.getKind() == Kind.Object) { throw new IllegalArgumentException("Return type not supported: " + returnType.getName()); } - ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(callNode.kind().toBoxedJavaClass()); - boxedResult = g.unique(new BoxNode(callNode, type, callNode.kind())); + ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(callNode.getKind().toBoxedJavaClass()); + boxedResult = g.unique(new BoxNode(callNode, type, callNode.getKind())); } else { boxedResult = g.unique(new BoxNode(ConstantNode.forLong(0, g), providers.getMetaAccess().lookupJavaType(Long.class), Kind.Long)); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,13 +30,14 @@ import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; /** * Reserves a block of memory in the stack frame of a method. The block is reserved in the frame for * the entire execution of the associated method. */ -public final class AllocaNode extends FixedWithNextNode implements LIRGenLowerable { +public final class AllocaNode extends FixedWithNextNode implements LIRGenResLowerable { /** * The number of slots in block. @@ -57,9 +58,9 @@ } @Override - public void generate(LIRGenerator gen) { - StackSlot array = gen.frameMap().allocateStackSlots(slots, objects, null); - Value result = gen.emitAddress(array); + public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) { + StackSlot array = res.getFrameMap().allocateStackSlots(slots, objects, null); + Value result = gen.getLIRGeneratorTool().emitAddress(array); gen.setResult(this, result); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -57,11 +57,11 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGenerator gen) { assert lockDepth != -1; - HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); StackSlot slot = hsGen.getLockSlot(lockDepth); - Value result = gen.emitAddress(slot); + Value result = gen.getLIRGeneratorTool().emitAddress(slot); gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,18 +22,17 @@ */ package com.oracle.graal.hotspot.nodes; -import static com.oracle.graal.graph.UnsafeAccess.*; - -import com.oracle.graal.nodes.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; /** - * Converts a compile-time constant Java string into a malloc'ed C string. The malloc'ed string is - * never reclaimed so this should only be used for strings in permanent code such as compiled stubs. + * Converts a compile-time constant Java string into a C string installed with the generated code. */ -public final class CStringNode extends FloatingNode implements Lowerable { +public final class CStringNode extends FloatingNode implements LIRGenLowerable { private final String string; @@ -42,16 +41,29 @@ this.string = string; } - @Override - public void lower(LoweringTool tool) { - byte[] formatBytes = string.getBytes(); - long cstring = unsafe.allocateMemory(formatBytes.length + 1); - for (int i = 0; i < formatBytes.length; i++) { - unsafe.putByte(cstring + i, formatBytes[i]); + public void generate(NodeLIRGenerator gen) { + gen.setResult(this, emitCString(gen, string)); + } + + public static AllocatableValue emitCString(NodeLIRGeneratorTool gen, String value) { + AllocatableValue dst = gen.getLIRGeneratorTool().newVariable(gen.getLIRGeneratorTool().target().wordKind); + gen.getLIRGeneratorTool().emitData(dst, toCString(value)); + return dst; + } + + /** + * Converts a string to a null terminated byte array of ASCII characters. + * + * @param s a String that must only contain ASCII characters + */ + public static byte[] toCString(String s) { + byte[] bytes = new byte[s.length() + 1]; + for (int i = 0; i < s.length(); i++) { + assert s.charAt(i) < 128 : "non-ascii string: " + s; + bytes[i] = (byte) s.charAt(i); } - unsafe.putByte(cstring + formatBytes.length, (byte) 0); - ConstantNode replacement = ConstantNode.forLong(cstring, graph()); - graph().replaceFloating(this, replacement); + bytes[s.length()] = 0; + return bytes; } @NodeIntrinsic(setStampFromReturnType = true) diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -41,9 +41,9 @@ } @Override - public void generate(LIRGeneratorTool gen) { - Register rawThread = ((HotSpotLIRGenerator) gen).getProviders().getRegisters().getThreadRegister(); - gen.setResult(this, rawThread.asValue(this.kind())); + public void generate(NodeLIRGeneratorTool gen) { + Register rawThread = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).getProviders().getRegisters().getThreadRegister(); + gen.setResult(this, rawThread.asValue(this.getKind())); } private static int eetopOffset() { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,16 +24,15 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; /** * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}. */ -public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable { +public final class CurrentLockNode extends FixedWithNextNode implements LIRLowerable { private int lockDepth; @@ -43,12 +42,12 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { assert lockDepth != -1; - HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); StackSlot slot = hsGen.getLockSlot(lockDepth); // The register allocator cannot handle stack -> register moves so we use an LEA here - Value result = gen.emitMove(gen.emitAddress(slot)); + Value result = gen.getLIRGeneratorTool().emitMove(gen.getLIRGeneratorTool().emitAddress(slot)); gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -45,8 +45,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - ((HotSpotLIRGenerator) gen).emitDeoptimizeCaller(action, reason); + public void generate(NodeLIRGeneratorTool gen) { + ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizeCaller(action, reason); } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -31,13 +31,14 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; /** * Intrinsic for allocating an on-stack array of integers to hold the dimensions of a multianewarray * instruction. */ -public final class DimensionsNode extends FixedWithNextNode implements LIRGenLowerable { +public final class DimensionsNode extends FixedWithNextNode implements LIRGenResLowerable { private final int rank; @@ -47,12 +48,12 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) { int size = rank * 4; - int wordSize = gen.target().wordSize; + int wordSize = gen.getLIRGeneratorTool().target().wordSize; int slots = roundUp(size, wordSize) / wordSize; - StackSlot array = gen.frameMap().allocateStackSlots(slots, new BitSet(0), null); - Value result = gen.emitAddress(array); + StackSlot array = res.getFrameMap().allocateStackSlots(slots, new BitSet(0), null); + Value result = gen.getLIRGeneratorTool().emitAddress(array); gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -77,8 +77,8 @@ } @Override - public void generate(LIRGenerator gen) { - ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this); + public void generate(NodeLIRGenerator gen) { + ((HotSpotNodeLIRGenerator) gen).visitDirectCompareAndSwap(this); } /** diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,17 +23,16 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; /** * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an * object. */ -public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRGenLowerable, MonitorExit, MemoryCheckpoint.Single { +public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorExit, MemoryCheckpoint.Single { public EndLockScopeNode() { super(StampFactory.forVoid()); @@ -50,7 +49,7 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java Sun Mar 30 16:08:33 2014 +0200 @@ -25,9 +25,9 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; -public class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode { +public class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode.DeoptBefore { - @Input private FrameState deoptimizationState; + @Input private FrameState stateBefore; private final boolean nullCheck; private final boolean doLoad; @@ -55,17 +55,13 @@ } @Override - public FrameState getDeoptimizationState() { - return deoptimizationState; + public FrameState stateBefore() { + return stateBefore; } @Override - public void setDeoptimizationState(FrameState state) { - updateUsages(deoptimizationState, state); - deoptimizationState = state; - } - - public FrameState getState() { - return deoptimizationState; + public void setStateBefore(FrameState state) { + updateUsages(stateBefore, state); + stateBefore = state; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -45,9 +45,9 @@ public static native long get(Object array); @Override - public void generate(LIRGeneratorTool gen) { - AllocatableValue obj = gen.newVariable(gen.target().wordKind); - gen.emitMove(obj, gen.operand(object)); + public void generate(NodeLIRGeneratorTool gen) { + AllocatableValue obj = gen.getLIRGeneratorTool().newVariable(gen.getLIRGeneratorTool().target().wordKind); + gen.getLIRGeneratorTool().emitMove(obj, gen.operand(object)); gen.setResult(this, obj); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -46,8 +46,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - ((HotSpotLIRGenerator) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc); + public void generate(NodeLIRGeneratorTool gen) { + ((HotSpotNodeLIRGenerator) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc); } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,22 +29,23 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; /** * Node that is used to maintain a stack based counter of how many locks are currently held. */ -public final class MonitorCounterNode extends FloatingNode implements LIRGenLowerable { +public final class MonitorCounterNode extends FloatingNode implements LIRGenResLowerable { private MonitorCounterNode() { super(null); } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) { assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance"; - StackSlot counter = gen.frameMap().allocateStackSlots(1, new BitSet(0), null); - Value result = gen.emitAddress(counter); + StackSlot counter = res.getFrameMap().allocateStackSlots(1, new BitSet(0), null); + Value result = gen.getLIRGeneratorTool().emitAddress(counter); gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Sun Mar 30 16:08:33 2014 +0200 @@ -47,12 +47,12 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGenerator gen) { assert lockDepth != -1; - HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); StackSlot slot = hsGen.getLockSlot(lockDepth); - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(MonitorExitStubCall.MONITOREXIT); - gen.emitForeignCall(linkage, this, gen.operand(object), gen.emitAddress(slot)); + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(MonitorExitStubCall.MONITOREXIT); + gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(object), gen.getLIRGeneratorTool().emitAddress(slot)); } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Sun Mar 30 16:08:33 2014 +0200 @@ -61,9 +61,9 @@ } @Override - public void generate(LIRGenerator gen) { - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(NEW_ARRAY); - Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length)); + public void generate(NodeLIRGenerator gen) { + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_ARRAY); + Variable result = gen.getLIRGenerator().emitForeignCall(linkage, this, gen.operand(hub), gen.operand(length)); gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,19 +24,17 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; -import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** * A call to the {@link NewInstanceStub}. */ -public class NewInstanceStubCall extends DeoptimizingStubCall implements LIRGenLowerable { +public class NewInstanceStubCall extends DeoptimizingStubCall implements LIRLowerable { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -59,9 +57,9 @@ } @Override - public void generate(LIRGenerator gen) { - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(NEW_INSTANCE); - Variable result = gen.emitForeignCall(linkage, this, gen.operand(hub)); + public void generate(NodeLIRGeneratorTool gen) { + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(NEW_INSTANCE); + Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(hub)); gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Sun Mar 30 16:08:33 2014 +0200 @@ -61,7 +61,7 @@ } @Override - protected Value[] operands(LIRGeneratorTool gen) { + protected Value[] operands(NodeLIRGeneratorTool gen) { return new Value[]{gen.operand(hub), Constant.forInt(rank), gen.operand(dims)}; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -41,8 +41,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - ((HotSpotLIRGenerator) gen).emitPatchReturnAddress(address); + public void generate(NodeLIRGeneratorTool gen) { + ((HotSpotNodeLIRGenerator) gen).emitPatchReturnAddress(address); } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -42,8 +42,8 @@ } @Override - public void generate(LIRGenerator gen) { - ((HotSpotLIRGenerator) gen).emitPrefetchAllocate(address, distance); + public void generate(NodeLIRGenerator gen) { + ((HotSpotNodeLIRGenerator) gen).emitPrefetchAllocate(address, distance); } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -57,7 +57,7 @@ return foreignCalls.getKilledLocations(descriptor); } - protected Value[] operands(LIRGeneratorTool gen) { + protected Value[] operands(NodeLIRGeneratorTool gen) { Value[] operands = new Value[arguments.size()]; for (int i = 0; i < operands.length; i++) { operands[i] = gen.operand(arguments.get(i)); @@ -66,11 +66,11 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { assert graph().start() instanceof StubStartNode; - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(descriptor); + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor); Value[] operands = operands(gen); - Value result = gen.emitForeignCall(linkage, null, operands); + Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, operands); if (result != null) { gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; @@ -40,7 +41,7 @@ * Performs a tail call to the specified target compiled method, with the parameter taken from the * supplied FrameState. */ -public class TailcallNode extends FixedWithNextNode implements LIRLowerable { +public class TailcallNode extends FixedWithNextNode implements LIRGenResLowerable { @Input private FrameState frameState; @Input private ValueNode target; @@ -57,22 +58,20 @@ this.frameState = frameState; } - @Override - public void generate(LIRGeneratorTool generator) { - LIRGenerator gen = (LIRGenerator) generator; + public void generate(NodeLIRGeneratorTool gen, LIRGenerationResult res) { HotSpotVMConfig config = runtime().getConfig(); ResolvedJavaMethod method = frameState.method(); boolean isStatic = Modifier.isStatic(method.getModifiers()); JavaType[] signature = MetaUtil.signatureToTypes(method.getSignature(), isStatic ? null : method.getDeclaringClass()); - CallingConvention cc = gen.frameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.target(), false); + CallingConvention cc = res.getFrameMap().registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, signature, gen.getLIRGeneratorTool().target(), false); List parameters = new ArrayList<>(); - for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += FrameStateBuilder.stackSlots(frameState.localAt(slot).kind())) { + for (int i = 0, slot = 0; i < cc.getArgumentCount(); i++, slot += HIRFrameStateBuilder.stackSlots(frameState.localAt(slot).getKind())) { parameters.add(frameState.localAt(slot)); } Value[] args = gen.visitInvokeArguments(cc, parameters); - Value address = gen.emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0); - Value entry = gen.emitLoad(Kind.Long, address, null); + Value address = gen.getLIRGeneratorTool().emitAddress(gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0); + Value entry = gen.getLIRGeneratorTool().emitLoad(Kind.Long, address, null); HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen; hsgen.emitTailcall(args, entry); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,11 +22,13 @@ */ package com.oracle.graal.hotspot.nodes; +import static com.oracle.graal.api.meta.MetaUtil.*; +import static com.oracle.graal.hotspot.nodes.CStringNode.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.*; @@ -34,31 +36,39 @@ * Causes the VM to exit with a description of the current Java location and an optional * {@linkplain Log#printf(String, long) formatted} error message specified. */ -public final class VMErrorNode extends DeoptimizingStubCall implements LIRGenLowerable { +public final class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable { private final String format; @Input private ValueNode value; public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); - private VMErrorNode(String format, ValueNode value) { + public VMErrorNode(String format, ValueNode value) { super(StampFactory.forVoid()); this.format = format; this.value = value; } @Override - public void generate(LIRGenerator gen) { - String whereString = "in compiled code for " + graph(); + public void generate(NodeLIRGeneratorTool gen) { + String whereString; + if (stateBefore() != null) { + String nl = CodeUtil.NEW_LINE; + StringBuilder sb = new StringBuilder("in compiled code associated with frame state:"); + FrameState fs = stateBefore(); + while (fs != null) { + MetaUtil.appendLocation(sb.append(nl).append("\t"), fs.method(), fs.bci); + fs = fs.outerFrameState(); + } + whereString = sb.toString(); + } else { + ResolvedJavaMethod method = graph().method(); + whereString = "in compiled code for " + (method == null ? graph().toString() : format("%H.%n(%p)", method)); + } + Value whereArg = emitCString(gen, whereString); + Value formatArg = emitCString(gen, format); - // As these strings will end up embedded as oops in the code, they - // must be interned or else they will cause the nmethod to be unloaded - // (nmethods are a) weak GC roots and b) unloaded if any of their - // embedded oops become unreachable). - Constant whereArg = Constant.forObject(whereString.intern()); - Constant formatArg = Constant.forObject(format.intern()); - - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(VMErrorNode.VM_ERROR); - gen.emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value)); + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(VMErrorNode.VM_ERROR); + gen.getLIRGeneratorTool().emitForeignCall(linkage, null, whereArg, formatArg, gen.operand(value)); } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,11 +29,13 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; +import edu.umd.cs.findbugs.annotations.*; + /** * Checks for illegal object constants in a graph processed for AOT compilation. The only legal * object constants are {@linkplain String#intern() interned} strings as they will be installed in * the Class Data Sharing (CDS) space. - * + * * @see LoadJavaMirrorWithKlassPhase */ public class AheadOfTimeVerificationPhase extends VerifyPhase { @@ -51,13 +53,14 @@ } private static boolean isObject(ConstantNode node) { - return node.kind() == Kind.Object; + return node.getKind() == Kind.Object; } private static boolean isNullReference(ConstantNode node) { return isObject(node) && node.asConstant().asObject() == null; } + @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want") private static boolean isInternedString(ConstantNode node) { if (!isObject(node)) { return false; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -68,9 +68,9 @@ protected static void addG1PreWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean doLoad, boolean nullCheck, StructuredGraph graph) { G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(object, value, location, doLoad, nullCheck)); - preBarrier.setDeoptimizationState(node.getDeoptimizationState()); + preBarrier.setStateBefore(node.stateBefore()); node.setNullCheck(false); - node.setDeoptimizationState(null); + node.setStateBefore(null); graph.addBeforeFixed(node, preBarrier); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,7 +27,6 @@ import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.Options.*; import static com.oracle.graal.nodes.PiArrayNode.*; -import static com.oracle.graal.nodes.PiNode.*; import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*; import static com.oracle.graal.phases.GraalOptions.*; import static com.oracle.graal.replacements.SnippetTemplate.*; @@ -139,7 +138,7 @@ if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, false); - result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, false); + result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, false, true); } else { new_stub.inc(); result = NewInstanceStubCall.call(hub); @@ -197,7 +196,7 @@ writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, true); newarray_loopInit.inc(); - result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll); + result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true); } else { newarray_stub.inc(); result = NewArrayStubCall.call(hub, length); @@ -251,7 +250,7 @@ * Computes the size of the memory chunk allocated for an array. This size accounts for the * array header size, boy size and any padding after the last element to satisfy object * alignment requirements. - * + * * @param length the number of elements in the array * @param alignment the object alignment requirement * @param headerSize the size of the array header @@ -277,7 +276,7 @@ } /** - * Maximum number of long stores to emit when zeroing an object with a constant size Larger + * Maximum number of long stores to emit when zeroing an object with a constant size. Larger * objects have their bodies initialized in a loop. */ private static final int MAX_UNROLLED_OBJECT_ZEROING_STORES = 8; @@ -285,14 +284,14 @@ /** * Zero uninitialized memory in a newly allocated object, unrolling as necessary and ensuring * that stores are aligned. - * + * * @param size number of bytes to zero * @param memory beginning of object which is being zeroed * @param constantSize is @ size} known to be constant in the snippet * @param startOffset offset to begin zeroing. May not be word aligned. * @param manualUnroll maximally unroll zeroing */ - private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean noAsserts) { + private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean noAsserts, boolean useSnippetCounters) { assert noAsserts || size % 8 == 0 : "unaligned object size"; int offset = startOffset; if (offset % 8 != 0) { @@ -305,7 +304,9 @@ // This case handles arrays of constant length. Instead of having a snippet variant for // each length, generate a chain of stores of maximum length. Once it's inlined the // break statement will trim excess stores. - new_seqInit.inc(); + if (useSnippetCounters) { + new_seqInit.inc(); + } explodeLoop(); for (int i = 0; i < MAX_UNROLLED_OBJECT_ZEROING_STORES; i++, offset += 8) { if (offset == size) { @@ -317,10 +318,14 @@ // Use Word instead of int to avoid extension to long in generated code Word off = Word.signed(offset); if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) { - new_seqInit.inc(); + if (useSnippetCounters) { + new_seqInit.inc(); + } explodeLoop(); } else { - new_loopInit.inc(); + if (useSnippetCounters) { + new_loopInit.inc(); + } } for (; off.rawValue() < size; off = off.add(8)) { memory.initializeLong(off, 0, INIT_LOCATION); @@ -333,17 +338,17 @@ * since they can't be compiled in stubs. */ public static Object formatObjectForStub(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord) { - return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, true); + return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, true, false); } /** * Formats some allocated memory with an object header and zeroes out the rest. */ - private static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean noAsserts) { + private static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean noAsserts, boolean useSnippetCounters) { Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord; initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { - zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, noAsserts); + zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, noAsserts, useSnippetCounters); } return memory.toObject(); } @@ -351,7 +356,8 @@ /** * Formats some allocated memory with an object header and zeroes out the rest. */ - public static Object formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll) { + public static Object formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll, + boolean useSnippetCounters) { memory.writeInt(arrayLengthOffset(), length, INIT_LOCATION); /* * store hub last as the concurrent garbage collectors assume length is valid if hub field @@ -359,7 +365,7 @@ */ initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { - zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, true); + zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, true, useSnippetCounters); } return memory.toObject(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Sun Mar 30 16:08:33 2014 +0200 @@ -83,7 +83,7 @@ /** * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to * -XX:-UseTLAB). - * + * * @param hub the hub of the object to be allocated * @param length the length of the array * @param intArrayHub the hub for {@code int[].class} @@ -110,7 +110,7 @@ if (logging()) { printf("newArray: allocated new array at %p\n", memory.rawValue()); } - return verifyObject(formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true, false)); + return verifyObject(formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true, false, false)); } } if (logging()) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Sun Mar 30 16:08:33 2014 +0200 @@ -97,7 +97,7 @@ /** * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to * -XX:-UseTLAB). - * + * * @param hub the hub of the object to be allocated * @param intArrayHub the hub for {@code int[].class} */ @@ -127,11 +127,11 @@ /** * Attempts to refill the current thread's TLAB and retries the allocation. - * + * * @param intArrayHub the hub for {@code int[].class} * @param sizeInBytes the size of the allocation * @param log specifies if logging is enabled - * + * * @return the newly allocated, uninitialized chunk of memory, or {@link Word#zero()} if the * operation was unsuccessful */ @@ -188,7 +188,7 @@ // an int int tlabFreeSpaceInInts = (int) tlabFreeSpaceInBytes >>> 2; int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts; - NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false, false); + NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false, false, false); long allocated = thread.readLong(threadAllocatedBytesOffset(), TLAB_THREAD_ALLOCATED_BYTES_LOCATION); allocated = allocated + top.subtract(readTlabStart(thread)).rawValue(); @@ -226,7 +226,7 @@ /** * Attempts to allocate a chunk of memory from Eden space. - * + * * @param sizeInBytes the size of the chunk to allocate * @param log specifies if logging is enabled * @return the allocated chunk or {@link Word#zero()} if allocation fails diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java --- a/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java Sun Mar 30 16:08:33 2014 +0200 @@ -118,6 +118,20 @@ public static final Register q14 = new Register(70, 14, "q14", CPU); public static final Register q15 = new Register(71, 15, "q15", CPU); + // non-allocatable registers used for deopt + public static final Register s32 = new Register(72, 32, "s32", CPU); + public static final Register s33 = new Register(73, 33, "s33", CPU); + public static final Register s34 = new Register(74, 34, "s34", CPU); + public static final Register s35 = new Register(75, 35, "s35", CPU); + public static final Register s36 = new Register(76, 36, "s36", CPU); + public static final Register s37 = new Register(77, 37, "s37", CPU); + public static final Register s38 = new Register(78, 38, "s38", CPU); + public static final Register s39 = new Register(79, 39, "s39", CPU); + public static final Register d16 = new Register(80, 16, "d16", CPU); + public static final Register d17 = new Register(81, 17, "d17", CPU); + public static final Register d18 = new Register(82, 18, "d18", CPU); + public static final Register d19 = new Register(83, 19, "d19", CPU); + // @formatter:off public static final Register[] cRegisters = { c0, c1, c2, c3, c4, c5, c6, c7 diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAILRegisterConfig.java --- a/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAILRegisterConfig.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAILRegisterConfig.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,7 +24,6 @@ package com.oracle.graal.hsail; import com.oracle.graal.api.code.*; - import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -168,6 +167,11 @@ } @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return false; + } + + @Override public CalleeSaveLayout getCalleeSaveLayout() { return null; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2014, 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.java; + +import com.oracle.graal.api.meta.*; + +public abstract class AbstractFrameStateBuilder { + + protected final ResolvedJavaMethod method; + protected int stackSize; + + public AbstractFrameStateBuilder(ResolvedJavaMethod method) { + this.method = method; + } + + protected AbstractFrameStateBuilder(AbstractFrameStateBuilder other) { + this.method = other.method; + } + + /** + * Returns the size of the local variables. + * + * @return the size of the local variables + */ + public abstract int localsSize(); + + /** + * Gets the current size (height) of the stack. + */ + public int stackSize() { + return stackSize; + } + + /** + * Gets the value in the local variables at the specified index, without any sanity checking. + * + * @param i the index into the locals + * @return the instruction that produced the value for the specified local + */ + public abstract T localAt(int i); + + /** + * Get the value on the stack at the specified stack index. + * + * @param i the index into the stack, with {@code 0} being the bottom of the stack + * @return the instruction at the specified position in the stack + */ + public abstract T stackAt(int i); + + /** + * Loads the local variable at the specified index, checking that the returned value is non-null + * and that two-stack values are properly handled. + * + * @param i the index of the local variable to load + * @return the instruction that produced the specified local + */ + public abstract T loadLocal(int i); + + /** + * Stores a given local variable at the specified index. If the value occupies two slots, then + * the next local variable index is also overwritten. + * + * @param i the index at which to store + * @param x the instruction which produces the value for the local + */ + public abstract void storeLocal(int i, T x); + + public abstract void storeStack(int i, T x); + + /** + * Pushes an instruction onto the stack with the expected type. + * + * @param kind the type expected for this instruction + * @param x the instruction to push onto the stack + */ + public abstract void push(Kind kind, T x); + + /** + * Pushes a value onto the stack without checking the type. + * + * @param x the instruction to push onto the stack + */ + public abstract void xpush(T x); + + /** + * Pushes a value onto the stack and checks that it is an int. + * + * @param x the instruction to push onto the stack + */ + public abstract void ipush(T x); + + /** + * Pushes a value onto the stack and checks that it is a float. + * + * @param x the instruction to push onto the stack + */ + public abstract void fpush(T x); + + /** + * Pushes a value onto the stack and checks that it is an object. + * + * @param x the instruction to push onto the stack + */ + public abstract void apush(T x); + + /** + * Pushes a value onto the stack and checks that it is a long. + * + * @param x the instruction to push onto the stack + */ + public abstract void lpush(T x); + + /** + * Pushes a value onto the stack and checks that it is a double. + * + * @param x the instruction to push onto the stack + */ + public abstract void dpush(T x); + + public abstract void pushReturn(Kind kind, T x); + + /** + * Pops an instruction off the stack with the expected type. + * + * @param kind the expected type + * @return the instruction on the top of the stack + */ + public abstract T pop(Kind kind); + + /** + * Pops a value off of the stack without checking the type. + * + * @return x the instruction popped off the stack + */ + public abstract T xpop(); + + /** + * Pops a value off of the stack and checks that it is an int. + * + * @return x the instruction popped off the stack + */ + public abstract T ipop(); + + /** + * Pops a value off of the stack and checks that it is a float. + * + * @return x the instruction popped off the stack + */ + public abstract T fpop(); + + /** + * Pops a value off of the stack and checks that it is an object. + * + * @return x the instruction popped off the stack + */ + public abstract T apop(); + + /** + * Pops a value off of the stack and checks that it is a long. + * + * @return x the instruction popped off the stack + */ + public abstract T lpop(); + + /** + * Pops a value off of the stack and checks that it is a double. + * + * @return x the instruction popped off the stack + */ + public abstract T dpop(); + + /** + * Pop the specified number of slots off of this stack and return them as an array of + * instructions. + * + * @return an array containing the arguments off of the stack + */ + public abstract T[] popArguments(int slotSize, int argSize); + + /** + * Peeks an element from the operand stack. + * + * @param argumentNumber The number of the argument, relative from the top of the stack (0 = + * top). Long and double arguments only count as one argument, i.e., null-slots are + * ignored. + * @return The peeked argument. + */ + public abstract T peek(int argumentNumber); + + public static int stackSlots(Kind kind) { + return isTwoSlot(kind) ? 2 : 1; + } + + /** + * Clears all values on this stack. + */ + public void clearStack() { + stackSize = 0; + } + + protected static boolean isTwoSlot(Kind kind) { + assert kind != Kind.Void && kind != Kind.Illegal; + return kind == Kind.Long || kind == Kind.Double; + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; /** * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow graph @@ -73,33 +74,40 @@ */ public final class BciBlockMapping { - public static class Block implements Cloneable { + public static class BciBlock extends AbstractBlockBase implements Cloneable { public int startBci; public int endBci; public boolean isExceptionEntry; public boolean isLoopHeader; public int loopId; - public int blockID; public FixedWithNextNode firstInstruction; - public FrameStateBuilder entryState; + public HIRFrameStateBuilder entryState; - public ArrayList successors = new ArrayList<>(2); + // public ArrayList successors = new ArrayList<>(2); + // public ArrayList predecessors = new ArrayList<>(2); // only used in the + // baseline + public long exits; private boolean visited; private boolean active; public long loops; - public HashMap jsrAlternatives; + public HashMap jsrAlternatives; public JsrScope jsrScope = JsrScope.EMPTY_SCOPE; - public Block jsrSuccessor; + public BciBlock jsrSuccessor; public int jsrReturnBci; - public Block retSuccessor; + public BciBlock retSuccessor; public boolean endsWithRet = false; - public Block exceptionDispatchBlock() { + public BciBlock() { + this.successors = new ArrayList<>(); + this.predecessors = new ArrayList<>(); + } + + public BciBlock exceptionDispatchBlock() { if (successors.size() > 0 && successors.get(successors.size() - 1) instanceof ExceptionDispatchBlock) { return successors.get(successors.size() - 1); } @@ -113,9 +121,9 @@ return successors.size(); } - public Block copy() { + public BciBlock copy() { try { - Block block = (Block) super.clone(); + BciBlock block = (BciBlock) super.clone(); block.successors = new ArrayList<>(successors); return block; } catch (CloneNotSupportedException e) { @@ -125,7 +133,7 @@ @Override public String toString() { - StringBuilder sb = new StringBuilder("B").append(blockID); + StringBuilder sb = new StringBuilder("B").append(getId()); sb.append('[').append(startBci).append("->").append(endBci); if (isLoopHeader || isExceptionEntry) { sb.append(' '); @@ -139,9 +147,41 @@ sb.append(']'); return sb.toString(); } + + public Loop getLoop() { + // TODO Auto-generated method stub + return null; + } + + public int getLoopDepth() { + // TODO Auto-generated method stub + return 0; + } + + public boolean isLoopHeader() { + return isLoopHeader; + } + + public boolean isLoopEnd() { + // TODO Auto-generated method stub + return false; + } + + public boolean isExceptionEntry() { + // TODO Auto-generated method stub + return false; + } + + public BciBlock getSuccessor(int index) { + return successors.get(index); + } + + public BciBlock getPredecessor(int index) { + return predecessors.get(index); + } } - public static class ExceptionDispatchBlock extends Block { + public static class ExceptionDispatchBlock extends BciBlock { private HashMap exceptionDispatch = new HashMap<>(); @@ -152,15 +192,15 @@ /** * The blocks found in this method, in reverse postorder. */ - public final List blocks; + public final List blocks; public final ResolvedJavaMethod method; public boolean hasJsrBytecodes; - public Block startBlock; + public BciBlock startBlock; private final BytecodeStream stream; private final ExceptionHandler[] exceptionHandlers; - private Block[] blockMap; - public Block[] loopHeaders; + private BciBlock[] blockMap; + public BciBlock[] loopHeaders; public LocalLiveness liveness; @@ -173,9 +213,9 @@ this.method = method; exceptionHandlers = method.getExceptionHandlers(); stream = new BytecodeStream(method.getCode()); - this.blockMap = new Block[method.getCodeSize()]; + this.blockMap = new BciBlock[method.getCodeSize()]; this.blocks = new ArrayList<>(); - this.loopHeaders = new Block[64]; + this.loopHeaders = new BciBlock[64]; } /** @@ -218,13 +258,13 @@ } private boolean verify() { - for (Block block : blocks) { - assert blocks.get(block.blockID) == block; + for (BciBlock block : blocks) { + assert blocks.get(block.getId()) == block; - for (int i = 0; i < block.successors.size(); i++) { - Block sux = block.successors.get(i); + for (int i = 0; i < block.getSuccessorCount(); i++) { + BciBlock sux = block.getSuccessor(i); if (sux instanceof ExceptionDispatchBlock) { - assert i == block.successors.size() - 1 : "Only one exception handler allowed, and it must be last in successors list"; + assert i == block.getSuccessorCount() - 1 : "Only one exception handler allowed, and it must be last in successors list"; } } } @@ -234,14 +274,14 @@ private void initializeBlockIds() { for (int i = 0; i < blocks.size(); i++) { - blocks.get(i).blockID = i; + blocks.get(i).setId(i); } } private void makeExceptionEntries() { // start basic blocks at all exception handler blocks and mark them as exception entries for (ExceptionHandler h : this.exceptionHandlers) { - Block xhandler = makeBlock(h.getHandlerBCI()); + BciBlock xhandler = makeBlock(h.getHandlerBCI()); xhandler.isExceptionEntry = true; } } @@ -250,13 +290,13 @@ // iterate over the bytecodes top to bottom. // mark the entrypoints of basic blocks and build lists of successors for // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret) - Block current = null; + BciBlock current = null; stream.setBCI(0); while (stream.currentBC() != Bytecodes.END) { int bci = stream.currentBCI(); if (current == null || blockMap[bci] != null) { - Block b = makeBlock(bci); + BciBlock b = makeBlock(bci); if (current != null) { addSuccessor(current.endBci, b); } @@ -327,7 +367,7 @@ if (target == 0) { throw new JsrNotSupportedBailout("jsr target bci 0 not allowed"); } - Block b1 = makeBlock(target); + BciBlock b1 = makeBlock(target); current.jsrSuccessor = b1; current.jsrReturnBci = stream.nextBCI(); current = null; @@ -382,10 +422,10 @@ } } - private Block makeBlock(int startBci) { - Block oldBlock = blockMap[startBci]; + private BciBlock makeBlock(int startBci) { + BciBlock oldBlock = blockMap[startBci]; if (oldBlock == null) { - Block newBlock = new Block(); + BciBlock newBlock = new BciBlock(); newBlock.startBci = startBci; blockMap[startBci] = newBlock; return newBlock; @@ -393,14 +433,14 @@ } else if (oldBlock.startBci != startBci) { // Backward branch into the middle of an already processed block. // Add the correct fall-through successor. - Block newBlock = new Block(); + BciBlock newBlock = new BciBlock(); newBlock.startBci = startBci; newBlock.endBci = oldBlock.endBci; - newBlock.successors.addAll(oldBlock.successors); + newBlock.getSuccessors().addAll(oldBlock.getSuccessors()); oldBlock.endBci = startBci - 1; - oldBlock.successors.clear(); - oldBlock.successors.add(newBlock); + oldBlock.getSuccessors().clear(); + oldBlock.getSuccessors().add(newBlock); for (int i = startBci; i <= newBlock.endBci; i++) { blockMap[i] = newBlock; @@ -424,30 +464,30 @@ } } - private void addSuccessor(int predBci, Block sux) { - Block predecessor = blockMap[predBci]; + private void addSuccessor(int predBci, BciBlock sux) { + BciBlock predecessor = blockMap[predBci]; if (sux.isExceptionEntry) { throw new BailoutException("Exception handler can be reached by both normal and exceptional control flow"); } - predecessor.successors.add(sux); + predecessor.getSuccessors().add(sux); } - private final ArrayList jsrVisited = new ArrayList<>(); + private final ArrayList jsrVisited = new ArrayList<>(); - private void createJsrAlternatives(Block block) { + private void createJsrAlternatives(BciBlock block) { jsrVisited.add(block); JsrScope scope = block.jsrScope; if (block.endsWithRet) { block.retSuccessor = blockMap[scope.nextReturnAddress()]; - block.successors.add(block.retSuccessor); + block.getSuccessors().add(block.retSuccessor); assert block.retSuccessor != block.jsrSuccessor; } - Debug.log("JSR alternatives block %s sux %s jsrSux %s retSux %s jsrScope %s", block, block.successors, block.jsrSuccessor, block.retSuccessor, block.jsrScope); + Debug.log("JSR alternatives block %s sux %s jsrSux %s retSux %s jsrScope %s", block, block.getSuccessors(), block.jsrSuccessor, block.retSuccessor, block.jsrScope); if (block.jsrSuccessor != null || !scope.isEmpty()) { - for (int i = 0; i < block.successors.size(); i++) { - Block successor = block.successors.get(i); + for (int i = 0; i < block.getSuccessorCount(); i++) { + BciBlock successor = block.getSuccessor(i); JsrScope nextScope = scope; if (successor == block.jsrSuccessor) { nextScope = scope.push(block.jsrReturnBci); @@ -459,7 +499,7 @@ throw new JsrNotSupportedBailout("unstructured control flow (" + successor.jsrScope + " " + nextScope + ")"); } if (!nextScope.isEmpty()) { - Block clone; + BciBlock clone; if (successor.jsrAlternatives != null && successor.jsrAlternatives.containsKey(nextScope)) { clone = successor.jsrAlternatives.get(nextScope); } else { @@ -470,7 +510,7 @@ clone.jsrScope = nextScope; successor.jsrAlternatives.put(nextScope, clone); } - block.successors.set(i, clone); + block.getSuccessors().set(i, clone); if (successor == block.jsrSuccessor) { block.jsrSuccessor = clone; } @@ -480,7 +520,7 @@ } } } - for (Block successor : block.successors) { + for (BciBlock successor : block.getSuccessors()) { if (!jsrVisited.contains(successor)) { createJsrAlternatives(successor); } @@ -509,9 +549,9 @@ curHandler.endBci = -1; curHandler.deoptBci = bci; curHandler.handler = h; - curHandler.successors.add(blockMap[h.getHandlerBCI()]); + curHandler.getSuccessors().add(blockMap[h.getHandlerBCI()]); if (lastHandler != null) { - curHandler.successors.add(lastHandler); + curHandler.getSuccessors().add(lastHandler); } exceptionDispatch.put(h, curHandler); } @@ -526,7 +566,7 @@ private void fixLoopBits() { do { loopChanges = false; - for (Block b : blocks) { + for (BciBlock b : blocks) { b.visited = false; } @@ -563,17 +603,17 @@ String n = System.lineSeparator(); StringBuilder sb = new StringBuilder(Debug.currentScope()).append("BlockMap ").append(name).append(" :"); sb.append(n); - Iterable it; + Iterable it; if (blocks.isEmpty()) { it = new HashSet<>(Arrays.asList(blockMap)); } else { it = blocks; } - for (Block b : it) { + for (BciBlock b : it) { if (b == null) { continue; } - sb.append("B").append(b.blockID).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")"); + sb.append("B").append(b.getId()).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")"); if (b.isLoopHeader) { sb.append(" LoopHeader"); } @@ -581,8 +621,8 @@ sb.append(" ExceptionEntry"); } sb.append(n).append(" Sux : "); - for (Block s : b.successors) { - sb.append("B").append(s.blockID).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")"); + for (BciBlock s : b.getSuccessors()) { + sb.append("B").append(s.getId()).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")"); if (s.isExceptionEntry) { sb.append("!"); } @@ -594,7 +634,7 @@ while (l != 0) { int lMask = 1 << pos; if ((l & lMask) != 0) { - sb.append("B").append(loopHeaders[pos].blockID).append(" "); + sb.append("B").append(loopHeaders[pos].getId()).append(" "); l &= ~lMask; } pos++; @@ -605,14 +645,14 @@ while (l != 0) { int lMask = 1 << pos; if ((l & lMask) != 0) { - sb.append("B").append(loopHeaders[pos].blockID).append(" "); + sb.append("B").append(loopHeaders[pos].getId()).append(" "); l &= ~lMask; } pos++; } sb.append(n); } - Debug.log(sb.toString()); + Debug.log("%s", sb); } } @@ -625,7 +665,7 @@ * Mark the block as a loop header, using the next available loop number. Also checks for corner * cases that we don't want to compile. */ - private void makeLoopHeader(Block block) { + private void makeLoopHeader(BciBlock block) { if (!block.isLoopHeader) { block.isLoopHeader = true; @@ -655,11 +695,11 @@ } /** - * Depth-first traversal of the control flow graph. The flag {@linkplain Block#visited} is used - * to visit every block only once. The flag {@linkplain Block#active} is used to detect cycles - * (backward edges). + * Depth-first traversal of the control flow graph. The flag {@linkplain BciBlock#visited} is + * used to visit every block only once. The flag {@linkplain BciBlock#active} is used to detect + * cycles (backward edges). */ - private long computeBlockOrder(Block block) { + private long computeBlockOrder(BciBlock block) { if (block.visited) { if (block.active) { // Reached block via backward branch. @@ -677,7 +717,7 @@ block.active = true; long loops = 0; - for (Block successor : block.successors) { + for (BciBlock successor : block.getSuccessors()) { // Recursively process successors. loops |= computeBlockOrder(successor); } @@ -695,7 +735,7 @@ return loops; } - private long fixLoopBits(Block block) { + private long fixLoopBits(BciBlock block) { if (block.visited) { // Return cached loop information for this block. if (block.isLoopHeader) { @@ -707,11 +747,11 @@ block.visited = true; long loops = block.loops; - for (Block successor : block.successors) { + for (BciBlock successor : block.getSuccessors()) { // Recursively process successors. loops |= fixLoopBits(successor); } - for (Block successor : block.successors) { + for (BciBlock successor : block.getSuccessors()) { successor.exits = loops & ~successor.loops; } if (block.loops != loops) { @@ -734,7 +774,7 @@ public abstract class LocalLiveness { private void computeLiveness() { - for (Block block : blocks) { + for (BciBlock block : blocks) { computeLocalLiveness(block); } @@ -744,22 +784,22 @@ Debug.log("Iteration %d", iteration); changed = false; for (int i = blocks.size() - 1; i >= 0; i--) { - Block block = blocks.get(i); - int blockID = block.blockID; + BciBlock block = blocks.get(i); + int blockID = block.getId(); // log statements in IFs because debugLiveX creates a new String if (Debug.isLogEnabled()) { - Debug.log(" start B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.blockID, block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), + Debug.logv(" start B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), debugLiveKill(blockID)); } boolean blockChanged = (iteration == 0); - if (block.successors.size() > 0) { + if (block.getSuccessorCount() > 0) { int oldCardinality = liveOutCardinality(blockID); - for (Block sux : block.successors) { + for (BciBlock sux : block.getSuccessors()) { if (Debug.isLogEnabled()) { - Debug.log(" Successor B%d: %s", sux.blockID, debugLiveIn(sux.blockID)); + Debug.log(" Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId())); } - propagateLiveness(blockID, sux.blockID); + propagateLiveness(blockID, sux.getId()); } blockChanged |= (oldCardinality != liveOutCardinality(blockID)); } @@ -767,7 +807,7 @@ if (blockChanged) { updateLiveness(blockID); if (Debug.isLogEnabled()) { - Debug.log(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.blockID, block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), + Debug.logv(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), debugLiveKill(blockID)); } } @@ -780,12 +820,12 @@ /** * Returns whether the local is live at the beginning of the given block. */ - public abstract boolean localIsLiveIn(Block block, int local); + public abstract boolean localIsLiveIn(BciBlock block, int local); /** * Returns whether the local is live at the end of the given block. */ - public abstract boolean localIsLiveOut(Block block, int local); + public abstract boolean localIsLiveOut(BciBlock block, int local); /** * Returns a string representation of the liveIn values of the given block. @@ -832,11 +872,11 @@ */ protected abstract void storeOne(int blockID, int local); - private void computeLocalLiveness(Block block) { + private void computeLocalLiveness(BciBlock block) { if (block.startBci < 0 || block.endBci < 0) { return; } - int blockID = block.blockID; + int blockID = block.getId(); stream.setBCI(block.startBci); while (stream.currentBCI() <= block.endBci) { switch (stream.currentBC()) { @@ -1043,14 +1083,14 @@ } @Override - public boolean localIsLiveIn(Block block, int local) { - int blockID = block.blockID; + public boolean localIsLiveIn(BciBlock block, int local) { + int blockID = block.getId(); return blockID >= Integer.MAX_VALUE ? false : (localsLiveIn[blockID] & (1L << local)) != 0L; } @Override - public boolean localIsLiveOut(Block block, int local) { - int blockID = block.blockID; + public boolean localIsLiveOut(BciBlock block, int local) { + int blockID = block.getId(); return blockID >= Integer.MAX_VALUE ? false : (localsLiveOut[blockID] & (1L << local)) != 0L; } } @@ -1128,13 +1168,13 @@ } @Override - public boolean localIsLiveIn(Block block, int local) { - return block.blockID >= Integer.MAX_VALUE ? true : localsLiveIn[block.blockID].get(local); + public boolean localIsLiveIn(BciBlock block, int local) { + return block.getId() >= Integer.MAX_VALUE ? true : localsLiveIn[block.getId()].get(local); } @Override - public boolean localIsLiveOut(Block block, int local) { - return block.blockID >= Integer.MAX_VALUE ? true : localsLiveOut[block.blockID].get(local); + public boolean localIsLiveOut(BciBlock block, int local) { + return block.getId() >= Integer.MAX_VALUE ? true : localsLiveOut[block.getId()].get(local); } } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParseHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParseHelper.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2014, 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.java; + +import static com.oracle.graal.bytecode.Bytecodes.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; + +public class BytecodeParseHelper { + + private AbstractFrameStateBuilder frameState; + + public BytecodeParseHelper(AbstractFrameStateBuilder frameState) { + this.frameState = frameState; + } + + public void setCurrentFrameState(AbstractFrameStateBuilder frameState) { + this.frameState = frameState; + } + + public void loadLocal(int index, Kind kind) { + frameState.push(kind, frameState.loadLocal(index)); + } + + public void storeLocal(Kind kind, int index) { + T value; + if (kind == Kind.Object) { + value = frameState.xpop(); + // astore and astore_ may be used to store a returnAddress (jsr) + assert value.getKind() == Kind.Object || value.getKind() == Kind.Int; + } else { + value = frameState.pop(kind); + } + frameState.storeLocal(index, value); + } + + public void stackOp(int opcode) { + switch (opcode) { + case POP: { + frameState.xpop(); + break; + } + case POP2: { + frameState.xpop(); + frameState.xpop(); + break; + } + case DUP: { + T w = frameState.xpop(); + frameState.xpush(w); + frameState.xpush(w); + break; + } + case DUP_X1: { + T w1 = frameState.xpop(); + T w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP_X2: { + T w1 = frameState.xpop(); + T w2 = frameState.xpop(); + T w3 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2: { + T w1 = frameState.xpop(); + T w2 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X1: { + T w1 = frameState.xpop(); + T w2 = frameState.xpop(); + T w3 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X2: { + T w1 = frameState.xpop(); + T w2 = frameState.xpop(); + T w3 = frameState.xpop(); + T w4 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w4); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case SWAP: { + T w1 = frameState.xpop(); + T w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + break; + } + default: + throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Wed Mar 19 11:43:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,698 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.java; - -import static com.oracle.graal.graph.iterators.NodePredicates.*; -import static com.oracle.graal.nodes.ValueNodeUtil.*; -import static java.lang.reflect.Modifier.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Node.Verbosity; -import com.oracle.graal.java.BciBlockMapping.Block; -import com.oracle.graal.java.BciBlockMapping.LocalLiveness; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -public class FrameStateBuilder { - - private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; - private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; - - private final ResolvedJavaMethod method; - private final StructuredGraph graph; - - private final ValueNode[] locals; - private final ValueNode[] stack; - private ValueNode[] lockedObjects; - private MonitorIdNode[] monitorIds; - - private int stackSize; - - /** - * @see BytecodeFrame#rethrowException - */ - private boolean rethrowException; - - public FrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean eagerResolve) { - assert graph != null; - this.method = method; - this.graph = graph; - this.locals = new ValueNode[method.getMaxLocals()]; - // we always need at least one stack slot (for exceptions) - this.stack = new ValueNode[Math.max(1, method.getMaxStackSize())]; - this.lockedObjects = EMPTY_ARRAY; - this.monitorIds = EMPTY_MONITOR_ARRAY; - - int javaIndex = 0; - int index = 0; - if (!isStatic(method.getModifiers())) { - // add the receiver - ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass()))); - storeLocal(javaIndex, receiver); - javaIndex = 1; - index = 1; - } - Signature sig = method.getSignature(); - int max = sig.getParameterCount(false); - ResolvedJavaType accessingClass = method.getDeclaringClass(); - for (int i = 0; i < max; i++) { - JavaType type = sig.getParameterType(i, accessingClass); - if (eagerResolve) { - type = type.resolve(accessingClass); - } - Kind kind = type.getKind().getStackKind(); - Stamp stamp; - if (kind == Kind.Object && type instanceof ResolvedJavaType) { - stamp = StampFactory.declared((ResolvedJavaType) type); - } else { - stamp = StampFactory.forKind(kind); - } - ParameterNode param = graph.unique(new ParameterNode(index, stamp)); - storeLocal(javaIndex, param); - javaIndex += stackSlots(kind); - index++; - } - } - - private FrameStateBuilder(FrameStateBuilder other) { - method = other.method; - graph = other.graph; - locals = other.locals.clone(); - stack = other.stack.clone(); - lockedObjects = other.lockedObjects == EMPTY_ARRAY ? EMPTY_ARRAY : other.lockedObjects.clone(); - monitorIds = other.monitorIds == EMPTY_MONITOR_ARRAY ? EMPTY_MONITOR_ARRAY : other.monitorIds.clone(); - stackSize = other.stackSize; - rethrowException = other.rethrowException; - - assert locals.length == method.getMaxLocals(); - assert stack.length == Math.max(1, method.getMaxStackSize()); - assert lockedObjects.length == monitorIds.length; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[locals: ["); - for (int i = 0; i < locals.length; i++) { - sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id)); - } - sb.append("] stack: ["); - for (int i = 0; i < stackSize; i++) { - sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); - } - sb.append("] locks: ["); - for (int i = 0; i < lockedObjects.length; i++) { - sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); - } - sb.append("]"); - if (rethrowException) { - sb.append(" rethrowException"); - } - sb.append("]"); - return sb.toString(); - } - - public FrameState create(int bci) { - return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), lockedObjects, monitorIds, rethrowException, false)); - } - - public FrameStateBuilder copy() { - return new FrameStateBuilder(this); - } - - public boolean isCompatibleWith(FrameStateBuilder other) { - assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; - assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; - - if (stackSize() != other.stackSize()) { - return false; - } - for (int i = 0; i < stackSize(); i++) { - ValueNode x = stackAt(i); - ValueNode y = other.stackAt(i); - if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.kind() != y.kind())) { - return false; - } - } - if (lockedObjects.length != other.lockedObjects.length) { - return false; - } - for (int i = 0; i < lockedObjects.length; i++) { - if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { - throw new BailoutException("unbalanced monitors"); - } - } - return true; - } - - public void merge(MergeNode block, FrameStateBuilder other) { - assert isCompatibleWith(other); - - for (int i = 0; i < localsSize(); i++) { - storeLocal(i, merge(localAt(i), other.localAt(i), block)); - } - for (int i = 0; i < stackSize(); i++) { - storeStack(i, merge(stackAt(i), other.stackAt(i), block)); - } - for (int i = 0; i < lockedObjects.length; i++) { - lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); - assert monitorIds[i] == other.monitorIds[i]; - } - } - - private ValueNode merge(ValueNode currentValue, ValueNode otherValue, MergeNode block) { - if (currentValue == null || currentValue.isDeleted()) { - return null; - - } else if (block.isPhiAtMerge(currentValue)) { - if (otherValue == null || otherValue.isDeleted() || currentValue.kind() != otherValue.kind()) { - propagateDelete((PhiNode) currentValue); - return null; - } - ((PhiNode) currentValue).addInput(otherValue); - return currentValue; - - } else if (currentValue != otherValue) { - assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for all locals and stack slots"; - if (otherValue == null || otherValue.isDeleted() || currentValue.kind() != otherValue.kind()) { - return null; - } - - PhiNode phi = graph.addWithoutUnique(new PhiNode(currentValue.stamp().unrestricted(), block)); - for (int i = 0; i < block.phiPredecessorCount(); i++) { - phi.addInput(currentValue); - } - phi.addInput(otherValue); - assert phi.valueCount() == block.phiPredecessorCount() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.phiPredecessorCount(); - return phi; - - } else { - return currentValue; - } - } - - private void propagateDelete(FloatingNode node) { - assert node instanceof PhiNode || node instanceof ProxyNode; - if (node.isDeleted()) { - return; - } - // Collect all phi functions that use this phi so that we can delete them recursively (after - // we delete ourselves to avoid circles). - List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ProxyNode.class)).snapshot(); - - // Remove the phi function from all FrameStates where it is used and then delete it. - assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; - node.replaceAtUsages(null); - node.safeDelete(); - - for (FloatingNode phiUsage : propagateUsages) { - propagateDelete(phiUsage); - } - } - - public void insertLoopPhis(LoopBeginNode loopBegin) { - for (int i = 0; i < localsSize(); i++) { - storeLocal(i, createLoopPhi(loopBegin, localAt(i))); - } - for (int i = 0; i < stackSize(); i++) { - storeStack(i, createLoopPhi(loopBegin, stackAt(i))); - } - for (int i = 0; i < lockedObjects.length; i++) { - lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]); - } - } - - public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) { - for (int i = 0; i < localsSize(); i++) { - ValueNode value = localAt(i); - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - storeLocal(i, ProxyNode.forValue(value, loopExit, graph)); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode value = stackAt(i); - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - storeStack(i, ProxyNode.forValue(value, loopExit, graph)); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - ValueNode value = lockedObjects[i]; - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); - } - } - } - - public void insertProxies(AbstractBeginNode begin) { - for (int i = 0; i < localsSize(); i++) { - ValueNode value = localAt(i); - if (value != null) { - Debug.log(" inserting proxy for %s", value); - storeLocal(i, ProxyNode.forValue(value, begin, graph)); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode value = stackAt(i); - if (value != null) { - Debug.log(" inserting proxy for %s", value); - storeStack(i, ProxyNode.forValue(value, begin, graph)); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - ValueNode value = lockedObjects[i]; - if (value != null) { - Debug.log(" inserting proxy for %s", value); - lockedObjects[i] = ProxyNode.forValue(value, begin, graph); - } - } - } - - private PhiNode createLoopPhi(MergeNode block, ValueNode value) { - if (value == null) { - return null; - } - assert !block.isPhiAtMerge(value) : "phi function for this block already created"; - - PhiNode phi = graph.addWithoutUnique(new PhiNode(value.stamp().unrestricted(), block)); - phi.addInput(value); - return phi; - } - - public void cleanupDeletedPhis() { - for (int i = 0; i < localsSize(); i++) { - if (localAt(i) != null && localAt(i).isDeleted()) { - assert localAt(i) instanceof PhiNode || localAt(i) instanceof ProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i); - storeLocal(i, null); - } - } - } - - public void clearNonLiveLocals(Block block, LocalLiveness liveness, boolean liveIn) { - if (liveness == null) { - return; - } - if (liveIn) { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveIn(block, i)) { - locals[i] = null; - } - } - } else { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveOut(block, i)) { - locals[i] = null; - } - } - } - } - - /** - * @see BytecodeFrame#rethrowException - */ - public boolean rethrowException() { - return rethrowException; - } - - /** - * @see BytecodeFrame#rethrowException - */ - public void setRethrowException(boolean b) { - rethrowException = b; - } - - /** - * Returns the size of the local variables. - * - * @return the size of the local variables - */ - public int localsSize() { - return locals.length; - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackSize; - } - - /** - * Gets the value in the local variables at the specified index, without any sanity checking. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public final ValueNode localAt(int i) { - return locals[i]; - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public final ValueNode stackAt(int i) { - return stack[i]; - } - - /** - * Adds a locked monitor to this frame state. - * - * @param object the object whose monitor will be locked. - */ - public void pushLock(ValueNode object, MonitorIdNode monitorId) { - assert object.isAlive() && object.kind() == Kind.Object : "unexpected value: " + object; - lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); - monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); - lockedObjects[lockedObjects.length - 1] = object; - monitorIds[monitorIds.length - 1] = monitorId; - assert lockedObjects.length == monitorIds.length; - } - - /** - * Removes a locked monitor from this frame state. - * - * @return the object whose monitor was removed from the locks list. - */ - public ValueNode popLock() { - try { - return lockedObjects[lockedObjects.length - 1]; - } finally { - lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); - monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); - } - } - - public MonitorIdNode peekMonitorId() { - return monitorIds[monitorIds.length - 1]; - } - - /** - * @return the current lock depth - */ - public int lockDepth() { - assert lockedObjects.length == monitorIds.length; - return lockedObjects.length; - } - - /** - * Loads the local variable at the specified index, checking that the returned value is non-null - * and that two-stack values are properly handled. - * - * @param i the index of the local variable to load - * @return the instruction that produced the specified local - */ - public ValueNode loadLocal(int i) { - ValueNode x = locals[i]; - assert !x.isDeleted(); - assert !isTwoSlot(x.kind()) || locals[i + 1] == null; - assert i == 0 || locals[i - 1] == null || !isTwoSlot(locals[i - 1].kind()); - return x; - } - - /** - * Stores a given local variable at the specified index. If the value occupies - * {@linkplain FrameStateBuilder#isTwoSlot(Kind) two slots}, then the next local variable index - * is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, ValueNode x) { - assert x == null || x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal : "unexpected value: " + x; - locals[i] = x; - if (x != null && isTwoSlot(x.kind())) { - // if this is a double word, then kill i+1 - locals[i + 1] = null; - } - if (x != null && i > 0) { - ValueNode p = locals[i - 1]; - if (p != null && isTwoSlot(p.kind())) { - // if there was a double word at i - 1, then kill it - locals[i - 1] = null; - } - } - } - - public void storeStack(int i, ValueNode x) { - assert x == null || x.isAlive() && (stack[i] == null || x.kind() == stack[i].kind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; - stack[i] = x; - } - - /** - * Pushes an instruction onto the stack with the expected type. - * - * @param kind the type expected for this instruction - * @param x the instruction to push onto the stack - */ - public void push(Kind kind, ValueNode x) { - assert x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal; - xpush(assertKind(kind, x)); - if (isTwoSlot(kind)) { - xpush(null); - } - } - - /** - * Pushes a value onto the stack without checking the type. - * - * @param x the instruction to push onto the stack - */ - public void xpush(ValueNode x) { - assert x == null || (x.isAlive() && x.kind() != Kind.Void && x.kind() != Kind.Illegal); - stack[stackSize++] = x; - } - - /** - * Pushes a value onto the stack and checks that it is an int. - * - * @param x the instruction to push onto the stack - */ - public void ipush(ValueNode x) { - xpush(assertInt(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a float. - * - * @param x the instruction to push onto the stack - */ - public void fpush(ValueNode x) { - xpush(assertFloat(x)); - } - - /** - * Pushes a value onto the stack and checks that it is an object. - * - * @param x the instruction to push onto the stack - */ - public void apush(ValueNode x) { - xpush(assertObject(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a long. - * - * @param x the instruction to push onto the stack - */ - public void lpush(ValueNode x) { - xpush(assertLong(x)); - xpush(null); - } - - /** - * Pushes a value onto the stack and checks that it is a double. - * - * @param x the instruction to push onto the stack - */ - public void dpush(ValueNode x) { - xpush(assertDouble(x)); - xpush(null); - } - - public void pushReturn(Kind kind, ValueNode x) { - if (kind != Kind.Void) { - push(kind.getStackKind(), x); - } - } - - /** - * Pops an instruction off the stack with the expected type. - * - * @param kind the expected type - * @return the instruction on the top of the stack - */ - public ValueNode pop(Kind kind) { - assert kind != Kind.Void; - if (isTwoSlot(kind)) { - xpop(); - } - return assertKind(kind, xpop()); - } - - /** - * Pops a value off of the stack without checking the type. - * - * @return x the instruction popped off the stack - */ - public ValueNode xpop() { - ValueNode result = stack[--stackSize]; - assert result == null || !result.isDeleted(); - return result; - } - - /** - * Pops a value off of the stack and checks that it is an int. - * - * @return x the instruction popped off the stack - */ - public ValueNode ipop() { - return assertInt(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a float. - * - * @return x the instruction popped off the stack - */ - public ValueNode fpop() { - return assertFloat(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is an object. - * - * @return x the instruction popped off the stack - */ - public ValueNode apop() { - return assertObject(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a long. - * - * @return x the instruction popped off the stack - */ - public ValueNode lpop() { - assertHigh(xpop()); - return assertLong(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a double. - * - * @return x the instruction popped off the stack - */ - public ValueNode dpop() { - assertHigh(xpop()); - return assertDouble(xpop()); - } - - /** - * Pop the specified number of slots off of this stack and return them as an array of - * instructions. - * - * @return an array containing the arguments off of the stack - */ - public ValueNode[] popArguments(int slotSize, int argSize) { - int base = stackSize - slotSize; - ValueNode[] r = new ValueNode[argSize]; - int argIndex = 0; - int stackindex = 0; - while (stackindex < slotSize) { - ValueNode element = stack[base + stackindex]; - assert element != null; - r[argIndex++] = element; - stackindex += stackSlots(element.kind()); - } - stackSize = base; - return r; - } - - /** - * Peeks an element from the operand stack. - * - * @param argumentNumber The number of the argument, relative from the top of the stack (0 = - * top). Long and double arguments only count as one argument, i.e., null-slots are - * ignored. - * @return The peeked argument. - */ - public ValueNode peek(int argumentNumber) { - int idx = stackSize() - 1; - for (int i = 0; i < argumentNumber; i++) { - if (stackAt(idx) == null) { - idx--; - assert isTwoSlot(stackAt(idx).kind()); - } - idx--; - } - return stackAt(idx); - } - - /** - * Clears all values on this stack. - */ - public void clearStack() { - stackSize = 0; - } - - public static int stackSlots(Kind kind) { - return isTwoSlot(kind) ? 2 : 1; - } - - public static boolean isTwoSlot(Kind kind) { - assert kind != Kind.Void && kind != Kind.Illegal; - return kind == Kind.Long || kind == Kind.Double; - } - - public boolean contains(ValueNode value) { - for (int i = 0; i < localsSize(); i++) { - if (localAt(i) == value) { - return true; - } - } - for (int i = 0; i < stackSize(); i++) { - if (stackAt(i) == value) { - return true; - } - } - assert lockedObjects.length == monitorIds.length; - for (int i = 0; i < lockedObjects.length; i++) { - if (lockedObjects[i] == value || monitorIds[i] == value) { - return true; - } - } - return false; - } -} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -40,7 +40,7 @@ import com.oracle.graal.bytecode.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.java.BciBlockMapping.Block; +import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; import com.oracle.graal.java.BciBlockMapping.LocalLiveness; import com.oracle.graal.nodes.*; @@ -117,8 +117,9 @@ private BytecodeStream stream; // the bytecode stream - protected FrameStateBuilder frameState; // the current execution state - private Block currentBlock; + protected HIRFrameStateBuilder frameState; // the current execution state + private BytecodeParseHelper parseHelper; + private BciBlock currentBlock; private ValueNode methodSynchronizedObject; private ExceptionDispatchBlock unwindBlock; @@ -139,7 +140,7 @@ * the jump. When the block is seen the second time, a {@link MergeNode} is created to * correctly merge the now two different predecessor states. */ - private static class BlockPlaceholderNode extends FixedWithNextNode { + protected static class BlockPlaceholderNode extends FixedWithNextNode { /* * Cannot be explicitly declared as a Node type since it is not an input; would cause @@ -159,13 +160,13 @@ } } - private Block[] loopHeaders; + private BciBlock[] loopHeaders; private LocalLiveness liveness; /** * Gets the current frame state being processed by this builder. */ - protected FrameStateBuilder getCurrentFrameState() { + protected HIRFrameStateBuilder getCurrentFrameState() { return frameState; } @@ -202,7 +203,8 @@ unwindBlock = null; methodSynchronizedObject = null; this.currentGraph = graph; - this.frameState = new FrameStateBuilder(method, graph, graphBuilderConfig.eagerResolving()); + this.frameState = new HIRFrameStateBuilder(method, graph, graphBuilderConfig.eagerResolving()); + this.parseHelper = new BytecodeParseHelper<>(frameState); TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); try { build(); @@ -222,76 +224,86 @@ TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), " ")); } - Indent indent = Debug.logAndIndent("build graph for %s", method); + try (Indent indent = Debug.logAndIndent("build graph for %s", method)) { - // compute the block map, setup exception handlers and get the entrypoint(s) - BciBlockMapping blockMap = BciBlockMapping.create(method); - loopHeaders = blockMap.loopHeaders; - liveness = blockMap.liveness; + // compute the block map, setup exception handlers and get the entrypoint(s) + BciBlockMapping blockMap = BciBlockMapping.create(method); + loopHeaders = blockMap.loopHeaders; + liveness = blockMap.liveness; - lastInstr = currentGraph.start(); - if (isSynchronized(method.getModifiers())) { - // add a monitor enter to the start block - currentGraph.start().setStateAfter(frameState.create(FrameState.BEFORE_BCI)); - methodSynchronizedObject = synchronizedObject(frameState, method); - lastInstr = genMonitorEnter(methodSynchronizedObject); - } - frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true); - ((StateSplit) lastInstr).setStateAfter(frameState.create(0)); + lastInstr = currentGraph.start(); + if (isSynchronized(method.getModifiers())) { + // add a monitor enter to the start block + currentGraph.start().setStateAfter(frameState.create(FrameState.BEFORE_BCI)); + methodSynchronizedObject = synchronizedObject(frameState, method); + lastInstr = genMonitorEnter(methodSynchronizedObject); + } + frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true); + ((StateSplit) lastInstr).setStateAfter(frameState.create(0)); + finishPrepare(lastInstr); - if (graphBuilderConfig.eagerInfopointMode()) { - InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0))); - lastInstr.setNext(ipn); - lastInstr = ipn; - } + if (graphBuilderConfig.eagerInfopointMode()) { + InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0))); + lastInstr.setNext(ipn); + lastInstr = ipn; + } - currentBlock = blockMap.startBlock; - blockMap.startBlock.entryState = frameState; - if (blockMap.startBlock.isLoopHeader) { - /* - * TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it - * expects currentBlock, etc. to be set up correctly. A better solution to this - * problem of start blocks that are loop headers would be to create a dummy block in - * BciBlockMapping. - */ - appendGoto(createTarget(blockMap.startBlock, frameState)); - } else { - blockMap.startBlock.firstInstruction = lastInstr; - } + currentBlock = blockMap.startBlock; + blockMap.startBlock.entryState = frameState; + if (blockMap.startBlock.isLoopHeader) { + /* + * TODO(lstadler,gduboscq) createTarget might not be safe at this position, + * since it expects currentBlock, etc. to be set up correctly. A better solution + * to this problem of start blocks that are loop headers would be to create a + * dummy block in BciBlockMapping. + */ + appendGoto(createTarget(blockMap.startBlock, frameState)); + } else { + blockMap.startBlock.firstInstruction = lastInstr; + } - for (Block block : blockMap.blocks) { - processBlock(block); - } - processBlock(unwindBlock); + for (BciBlock block : blockMap.blocks) { + processBlock(block); + } + processBlock(unwindBlock); - Debug.dump(currentGraph, "After bytecode parsing"); + Debug.dump(currentGraph, "After bytecode parsing"); + + connectLoopEndToBegin(); - connectLoopEndToBegin(); + // remove Placeholders + for (BlockPlaceholderNode n = placeholders; n != null; n = n.nextPlaceholder()) { + if (!n.isDeleted()) { + currentGraph.removeFixed(n); + } + } + placeholders = null; - // remove Placeholders - for (BlockPlaceholderNode n = placeholders; n != null; n = n.nextPlaceholder()) { - if (!n.isDeleted()) { - currentGraph.removeFixed(n); + // remove dead FrameStates + for (Node n : currentGraph.getNodes(FrameState.class)) { + if (n.usages().isEmpty() && n.predecessor() == null) { + n.safeDelete(); + } } } - placeholders = null; - - // remove dead FrameStates - for (Node n : currentGraph.getNodes(FrameState.class)) { - if (n.usages().isEmpty() && n.predecessor() == null) { - n.safeDelete(); - } - } - indent.outdent(); } - private Block unwindBlock(int bci) { + /** + * A hook for derived classes to modify the graph start instruction or append new + * instructions to it. + * + * @param startInstr The start instruction of the graph. + */ + protected void finishPrepare(FixedWithNextNode startInstr) { + } + + private BciBlock unwindBlock(int bci) { if (unwindBlock == null) { unwindBlock = new ExceptionDispatchBlock(); unwindBlock.startBci = -1; unwindBlock.endBci = -1; unwindBlock.deoptBci = bci; - unwindBlock.blockID = Integer.MAX_VALUE; + unwindBlock.setId(Integer.MAX_VALUE); } return unwindBlock; } @@ -304,6 +316,7 @@ return stream.currentBCI(); } + @SuppressWarnings("unused") private void loadLocal(int index, Kind kind) { frameState.push(kind, frameState.loadLocal(index)); } @@ -313,7 +326,7 @@ if (kind == Kind.Object) { value = frameState.xpop(); // astore and astore_ may be used to store a returnAddress (jsr) - assert value.kind() == Kind.Object || value.kind() == Kind.Int; + assert value.getKind() == Kind.Object || value.getKind() == Kind.Int; } else { value = frameState.pop(kind); } @@ -428,7 +441,7 @@ assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci"; Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, profilingInfo.getExceptionSeen(bci)); - Block dispatchBlock = currentBlock.exceptionDispatchBlock(); + BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock(); /* * The exception dispatch block is always for the last bytecode of a block, so if we are * not at the endBci yet, there is no exception handler for this bci and we can unwind @@ -438,7 +451,7 @@ dispatchBlock = unwindBlock(bci); } - FrameStateBuilder dispatchState = frameState.copy(); + HIRFrameStateBuilder dispatchState = frameState.copy(); dispatchState.clearStack(); DispatchBeginNode dispatchBegin; @@ -454,7 +467,7 @@ dispatchState.setRethrowException(true); } FixedNode target = createTarget(dispatchBlock, dispatchState); - dispatchBegin.setNext(target); + finishInstruction(dispatchBegin, dispatchState).setNext(target); return dispatchBegin; } @@ -572,7 +585,6 @@ default: throw GraalInternalError.shouldNotReachHere(); } - } private void genArithmeticOp(Kind result, int opcode) { @@ -730,15 +742,15 @@ } private void genGoto() { - appendGoto(createTarget(currentBlock.successors.get(0), frameState)); + appendGoto(createTarget(currentBlock.getSuccessor(0), frameState)); assert currentBlock.numNormalSuccessors() == 1; } private void ifNode(ValueNode x, Condition cond, ValueNode y) { assert !x.isDeleted() && !y.isDeleted(); assert currentBlock.numNormalSuccessors() == 2; - Block trueBlock = currentBlock.successors.get(0); - Block falseBlock = currentBlock.successors.get(1); + BciBlock trueBlock = currentBlock.getSuccessor(0); + BciBlock falseBlock = currentBlock.getSuccessor(1); if (trueBlock == falseBlock) { appendGoto(createTarget(trueBlock, frameState)); return; @@ -767,15 +779,15 @@ ValueNode b = mirror ? x : y; CompareNode condition; - assert !a.kind().isNumericFloat(); + assert !a.getKind().isNumericFloat(); if (cond == Condition.EQ || cond == Condition.NE) { - if (a.kind() == Kind.Object) { + if (a.getKind() == Kind.Object) { condition = new ObjectEqualsNode(a, b); } else { condition = new IntegerEqualsNode(a, b); } } else { - assert a.kind() != Kind.Object && !cond.isUnsigned(); + assert a.getKind() != Kind.Object && !cond.isUnsigned(); condition = new IntegerLessThanNode(a, b); } condition = currentGraph.unique(condition); @@ -902,7 +914,7 @@ /** * Gets the kind of array elements for the array type code that appears in a * {@link Bytecodes#NEWARRAY} bytecode. - * + * * @param code the array type code * @return the kind from the array type code */ @@ -1113,7 +1125,7 @@ private void genInvokeInterface(JavaMethod target) { if (target instanceof ResolvedJavaMethod) { ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true)); - genInvokeIndirect(InvokeKind.Interface, (ResolvedJavaMethod) target, args); + appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args); } else { handleUnresolvedInvoke(target, InvokeKind.Interface); } @@ -1148,7 +1160,7 @@ } ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(hasReceiver), target.getSignature().getParameterCount(hasReceiver)); if (hasReceiver) { - genInvokeIndirect(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); } else { appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); } @@ -1163,47 +1175,12 @@ assert target != null; assert target.getSignature() != null; ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true)); - invokeDirect((ResolvedJavaMethod) target, args); + appendInvoke(InvokeKind.Special, (ResolvedJavaMethod) target, args); } else { handleUnresolvedInvoke(target, InvokeKind.Special); } } - private void genInvokeIndirect(InvokeKind invokeKind, ResolvedJavaMethod target, ValueNode[] args) { - ValueNode receiver = args[0]; - // attempt to devirtualize the call - ResolvedJavaType klass = target.getDeclaringClass(); - - // 0. check for trivial cases - if (target.canBeStaticallyBound()) { - // check for trivial cases (e.g. final methods, nonvirtual methods) - invokeDirect(target, args); - return; - } - // 1. check if the exact type of the receiver can be determined - ResolvedJavaType exact = klass.asExactType(); - if (exact == null && receiver.stamp() instanceof ObjectStamp) { - ObjectStamp receiverStamp = (ObjectStamp) receiver.stamp(); - if (receiverStamp.isExactType()) { - exact = receiverStamp.type(); - } - } - if (exact != null) { - // either the holder class is exact, or the receiver object has an exact type - ResolvedJavaMethod exactMethod = exact.resolveMethod(target); - if (exactMethod != null) { - invokeDirect(exactMethod, args); - return; - } - } - // devirtualization failed, produce an actual invokevirtual - appendInvoke(invokeKind, target, args); - } - - private void invokeDirect(ResolvedJavaMethod target, ValueNode[] args) { - appendInvoke(InvokeKind.Special, target, args); - } - private void appendInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { Kind resultType = targetMethod.getSignature().getReturnKind(); if (DeoptALot.getValue()) { @@ -1235,7 +1212,7 @@ InvokeWithExceptionNode invoke = createInvokeWithException(callTarget, resultType); - Block nextBlock = currentBlock.successors.get(0); + BciBlock nextBlock = currentBlock.getSuccessor(0); invoke.setNext(createTarget(nextBlock, frameState)); } } @@ -1254,7 +1231,7 @@ DispatchBeginNode exceptionEdge = handleException(null, bci()); InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); frameState.pushReturn(resultType, invoke); - Block nextBlock = currentBlock.successors.get(0); + BciBlock nextBlock = currentBlock.getSuccessor(0); invoke.setStateAfter(frameState.create(nextBlock.startBci)); return invoke; } @@ -1292,7 +1269,7 @@ } private void genJsr(int dest) { - Block successor = currentBlock.jsrSuccessor; + BciBlock successor = currentBlock.jsrSuccessor; assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci(); JsrScope scope = currentBlock.jsrScope; if (!successor.jsrScope.pop().equals(scope)) { @@ -1306,7 +1283,7 @@ } private void genRet(int localIndex) { - Block successor = currentBlock.retSuccessor; + BciBlock successor = currentBlock.retSuccessor; ValueNode local = frameState.loadLocal(localIndex); JsrScope scope = currentBlock.jsrScope; int retAddress = scope.nextReturnAddress(); @@ -1344,7 +1321,7 @@ /** * Helper function that sums up the probabilities of all keys that lead to a specific * successor. - * + * * @return an array of size successorCount with the accumulated probability for each * successor. */ @@ -1364,14 +1341,14 @@ double[] keyProbabilities = switchProbability(nofCases + 1, bci); Map bciToBlockSuccessorIndex = new HashMap<>(); - for (int i = 0; i < currentBlock.successors.size(); i++) { - assert !bciToBlockSuccessorIndex.containsKey(currentBlock.successors.get(i).startBci); - if (!bciToBlockSuccessorIndex.containsKey(currentBlock.successors.get(i).startBci)) { - bciToBlockSuccessorIndex.put(currentBlock.successors.get(i).startBci, new SuccessorInfo(i)); + for (int i = 0; i < currentBlock.getSuccessorCount(); i++) { + assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci); + if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) { + bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i)); } } - ArrayList actualSuccessors = new ArrayList<>(); + ArrayList actualSuccessors = new ArrayList<>(); int[] keys = new int[nofCases]; int[] keySuccessors = new int[nofCases + 1]; int deoptSuccessorIndex = -1; @@ -1392,7 +1369,7 @@ SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); if (info.actualIndex < 0) { info.actualIndex = nextSuccessorIndex++; - actualSuccessors.add(currentBlock.successors.get(info.blockIndex)); + actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex)); } keySuccessors[i] = info.actualIndex; } @@ -1458,15 +1435,15 @@ private static class Target { FixedNode fixed; - FrameStateBuilder state; + HIRFrameStateBuilder state; - public Target(FixedNode fixed, FrameStateBuilder state) { + public Target(FixedNode fixed, HIRFrameStateBuilder state) { this.fixed = fixed; this.state = state; } } - private Target checkLoopExit(FixedNode target, Block targetBlock, FrameStateBuilder state) { + private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) { if (currentBlock != null) { long exits = currentBlock.loops & ~targetBlock.loops; if (exits != 0) { @@ -1474,7 +1451,7 @@ LoopExitNode lastLoopExit = null; int pos = 0; - ArrayList exitLoops = new ArrayList<>(Long.bitCount(exits)); + ArrayList exitLoops = new ArrayList<>(Long.bitCount(exits)); do { long lMask = 1L << pos; if ((exits & lMask) != 0) { @@ -1484,10 +1461,10 @@ pos++; } while (exits != 0); - Collections.sort(exitLoops, new Comparator() { + Collections.sort(exitLoops, new Comparator() { @Override - public int compare(Block o1, Block o2) { + public int compare(BciBlock o1, BciBlock o2) { return Long.bitCount(o2.loops) - Long.bitCount(o1.loops); } }); @@ -1496,8 +1473,8 @@ if (targetBlock instanceof ExceptionDispatchBlock) { bci = ((ExceptionDispatchBlock) targetBlock).deoptBci; } - FrameStateBuilder newState = state.copy(); - for (Block loop : exitLoops) { + HIRFrameStateBuilder newState = state.copy(); + for (BciBlock loop : exitLoops) { LoopBeginNode loopBegin = (LoopBeginNode) loop.firstInstruction; LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin)); if (lastLoopExit != null) { @@ -1519,7 +1496,7 @@ return new Target(target, state); } - private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) { + private FixedNode createTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) { assert probability >= 0 && probability <= 1.01 : probability; if (isNeverExecutedCode(probability)) { return currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); @@ -1533,7 +1510,7 @@ return probability == 0 && optimisticOpts.removeNeverExecutedCode() && entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI; } - private FixedNode createTarget(Block block, FrameStateBuilder state) { + private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) { assert block != null && state != null; assert !block.isExceptionEntry || state.stackSize() == 1; @@ -1559,7 +1536,7 @@ } if (block.firstInstruction instanceof LoopBeginNode) { - assert block.isLoopHeader && currentBlock.blockID >= block.blockID : "must be backward branch"; + assert block.isLoopHeader && currentBlock.getId() >= block.getId() : "must be backward branch"; /* * Backward loop edge. We need to create a special LoopEndNode and merge with the * loop begin node created before. @@ -1572,7 +1549,7 @@ Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); return result; } - assert currentBlock == null || currentBlock.blockID < block.blockID : "must not be backward branch"; + assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch"; assert block.firstInstruction.next() == null : "bytecodes already parsed for block"; if (block.firstInstruction instanceof BlockPlaceholderNode) { @@ -1613,7 +1590,7 @@ * Returns a block begin node with the specified state. If the specified probability is 0, * the block deoptimizes immediately. */ - private AbstractBeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) { + private AbstractBeginNode createBlockTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) { FixedNode target = createTarget(probability, block, stateAfter); AbstractBeginNode begin = AbstractBeginNode.begin(target); @@ -1622,7 +1599,7 @@ return begin; } - private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) { + private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) { if (isStatic(target.getModifiers())) { return appendConstant(target.getDeclaringClass().getEncoding(Representation.JavaClass)); } else { @@ -1630,37 +1607,38 @@ } } - private void processBlock(Block block) { + private void processBlock(BciBlock block) { // Ignore blocks that have no predecessors by the time their bytecodes are parsed if (block == null || block.firstInstruction == null) { Debug.log("Ignoring block %s", block); return; } - Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader); + try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader)) { - lastInstr = block.firstInstruction; - frameState = block.entryState; - currentBlock = block; + lastInstr = block.firstInstruction; + frameState = block.entryState; + parseHelper.setCurrentFrameState(frameState); + currentBlock = block; - frameState.cleanupDeletedPhis(); - if (lastInstr instanceof MergeNode) { - int bci = block.startBci; - if (block instanceof ExceptionDispatchBlock) { - bci = ((ExceptionDispatchBlock) block).deoptBci; + frameState.cleanupDeletedPhis(); + if (lastInstr instanceof MergeNode) { + int bci = block.startBci; + if (block instanceof ExceptionDispatchBlock) { + bci = ((ExceptionDispatchBlock) block).deoptBci; + } + ((MergeNode) lastInstr).setStateAfter(frameState.create(bci)); } - ((MergeNode) lastInstr).setStateAfter(frameState.create(bci)); + + if (block == unwindBlock) { + frameState.setRethrowException(false); + createUnwind(); + } else if (block instanceof ExceptionDispatchBlock) { + createExceptionDispatch((ExceptionDispatchBlock) block); + } else { + frameState.setRethrowException(false); + iterateBytecodesForBlock(block); + } } - - if (block == unwindBlock) { - frameState.setRethrowException(false); - createUnwind(); - } else if (block instanceof ExceptionDispatchBlock) { - createExceptionDispatch((ExceptionDispatchBlock) block); - } else { - frameState.setRethrowException(false); - iterateBytecodesForBlock(block); - } - indent.outdent(); } private void connectLoopEndToBegin() { @@ -1696,7 +1674,7 @@ if (Modifier.isSynchronized(method.getModifiers())) { MonitorExitNode monitorExit = genMonitorExit(methodSynchronizedObject, returnValue); if (returnValue != null) { - frameState.push(returnValue.kind(), returnValue); + frameState.push(returnValue.getKind(), returnValue); } monitorExit.setStateAfter(frameState.create(bci)); assert !frameState.rethrowException(); @@ -1706,8 +1684,8 @@ private void createExceptionDispatch(ExceptionDispatchBlock block) { assert frameState.stackSize() == 1 : frameState; if (block.handler.isCatchAll()) { - assert block.successors.size() == 1; - appendGoto(createTarget(block.successors.get(0), frameState)); + assert block.getSuccessorCount() == 1; + appendGoto(createTarget(block.getSuccessor(0), frameState)); return; } @@ -1720,7 +1698,7 @@ ResolvedJavaType resolvedCatchType = (ResolvedJavaType) catchType; for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) { if (skippedType.isAssignableFrom(resolvedCatchType)) { - Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1); + BciBlock nextBlock = block.getSuccessorCount() == 1 ? unwindBlock(block.deoptBci) : block.getSuccessor(1); ValueNode exception = frameState.stackAt(0); FixedNode trueSuccessor = currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); FixedNode nextDispatch = createTarget(nextBlock, frameState); @@ -1731,12 +1709,12 @@ } if (initialized) { - Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1); + BciBlock nextBlock = block.getSuccessorCount() == 1 ? unwindBlock(block.deoptBci) : block.getSuccessor(1); ValueNode exception = frameState.stackAt(0); CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false)); frameState.apop(); frameState.push(Kind.Object, checkCast); - FixedNode catchSuccessor = createTarget(block.successors.get(0), frameState); + FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState); frameState.apop(); frameState.push(Kind.Object, exception); FixedNode nextDispatch = createTarget(nextBlock, frameState); @@ -1757,7 +1735,7 @@ return n instanceof ControlSplitNode || n instanceof ControlSinkNode; } - private void iterateBytecodesForBlock(Block block) { + private void iterateBytecodesForBlock(BciBlock block) { if (block.isLoopHeader) { // Create the loop header block, which later will merge the backward branches of the // loop. @@ -1789,6 +1767,8 @@ assert lastInstr.next() == null : "instructions already appended at block " + block; Debug.log(" frameState: %s", frameState); + lastInstr = finishInstruction(lastInstr, frameState); + int endBCI = stream.endBCI(); stream.setBCI(block.startBci); @@ -1838,18 +1818,30 @@ } } } + lastInstr = finishInstruction(lastInstr, frameState); if (bci < endBCI) { if (bci > block.endBci) { - assert !block.successors.get(0).isExceptionEntry; + assert !block.getSuccessor(0).isExceptionEntry; assert block.numNormalSuccessors() == 1; // we fell through to the next block, add a goto and break - appendGoto(createTarget(block.successors.get(0), frameState)); + appendGoto(createTarget(block.getSuccessor(0), frameState)); break; } } } } + /** + * A hook for derived classes to modify the last instruction or add other instructions. + * + * @param instr The last instruction (= fixed node) which was added. + * @param state The current frame state. + * @Returns Returns the (new) last instruction. + */ + protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, HIRFrameStateBuilder state) { + return instr; + } + private final int traceLevel = Options.TraceBytecodeParserLevel.getValue(); private void traceState() { @@ -1857,11 +1849,11 @@ Debug.log(String.format("| state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method)); for (int i = 0; i < frameState.localsSize(); ++i) { ValueNode value = frameState.localAt(i); - Debug.log(String.format("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind().getJavaName(), value)); + Debug.log(String.format("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value)); } for (int i = 0; i < frameState.stackSize(); ++i) { ValueNode value = frameState.stackAt(i); - Debug.log(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind().getJavaName(), value)); + Debug.log(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.getKind().getJavaName(), value)); } } } @@ -1893,31 +1885,31 @@ case LDC : // fall through case LDC_W : // fall through case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; - case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; - case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; - case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; - case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; - case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; + case ILOAD : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Int); break; + case LLOAD : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Long); break; + case FLOAD : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Float); break; + case DLOAD : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Double); break; + case ALOAD : parseHelper.loadLocal(stream.readLocalIndex(), Kind.Object); break; case ILOAD_0 : // fall through case ILOAD_1 : // fall through case ILOAD_2 : // fall through - case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; + case ILOAD_3 : parseHelper.loadLocal(opcode - ILOAD_0, Kind.Int); break; case LLOAD_0 : // fall through case LLOAD_1 : // fall through case LLOAD_2 : // fall through - case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; + case LLOAD_3 : parseHelper.loadLocal(opcode - LLOAD_0, Kind.Long); break; case FLOAD_0 : // fall through case FLOAD_1 : // fall through case FLOAD_2 : // fall through - case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; + case FLOAD_3 : parseHelper.loadLocal(opcode - FLOAD_0, Kind.Float); break; case DLOAD_0 : // fall through case DLOAD_1 : // fall through case DLOAD_2 : // fall through - case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; + case DLOAD_3 : parseHelper.loadLocal(opcode - DLOAD_0, Kind.Double); break; case ALOAD_0 : // fall through case ALOAD_1 : // fall through case ALOAD_2 : // fall through - case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; + case ALOAD_3 : parseHelper.loadLocal(opcode - ALOAD_0, Kind.Object); break; case IALOAD : genLoadIndexed(Kind.Int ); break; case LALOAD : genLoadIndexed(Kind.Long ); break; case FALOAD : genLoadIndexed(Kind.Float ); break; @@ -2098,7 +2090,7 @@ if (!currentBlock.jsrScope.isEmpty()) { sb.append(' ').append(currentBlock.jsrScope); } - Debug.log(sb.toString()); + Debug.log("%s", sb); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.java; + +import static com.oracle.graal.graph.iterators.NodePredicates.*; +import static com.oracle.graal.nodes.ValueNodeUtil.*; +import static java.lang.reflect.Modifier.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.Node.Verbosity; +import com.oracle.graal.java.BciBlockMapping.BciBlock; +import com.oracle.graal.java.BciBlockMapping.LocalLiveness; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +public class HIRFrameStateBuilder extends AbstractFrameStateBuilder { + + private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; + + private final ValueNode[] locals; + private final ValueNode[] stack; + private ValueNode[] lockedObjects; + private MonitorIdNode[] monitorIds; + private final StructuredGraph graph; + + /** + * @see BytecodeFrame#rethrowException + */ + private boolean rethrowException; + + public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean eagerResolve) { + super(method); + + assert graph != null; + + this.locals = new ValueNode[method.getMaxLocals()]; + // we always need at least one stack slot (for exceptions) + this.stack = new ValueNode[Math.max(1, method.getMaxStackSize())]; + this.lockedObjects = EMPTY_ARRAY; + this.monitorIds = EMPTY_MONITOR_ARRAY; + this.graph = graph; + + int javaIndex = 0; + int index = 0; + if (!isStatic(method.getModifiers())) { + // add the receiver + ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass()))); + storeLocal(javaIndex, receiver); + javaIndex = 1; + index = 1; + } + Signature sig = method.getSignature(); + int max = sig.getParameterCount(false); + ResolvedJavaType accessingClass = method.getDeclaringClass(); + for (int i = 0; i < max; i++) { + JavaType type = sig.getParameterType(i, accessingClass); + if (eagerResolve) { + type = type.resolve(accessingClass); + } + Kind kind = type.getKind().getStackKind(); + Stamp stamp; + if (kind == Kind.Object && type instanceof ResolvedJavaType) { + stamp = StampFactory.declared((ResolvedJavaType) type); + } else { + stamp = StampFactory.forKind(kind); + } + ParameterNode param = graph.unique(new ParameterNode(index, stamp)); + storeLocal(javaIndex, param); + javaIndex += stackSlots(kind); + index++; + } + } + + private HIRFrameStateBuilder(HIRFrameStateBuilder other) { + super(other); + assert other.graph != null; + graph = other.graph; + locals = other.locals.clone(); + stack = other.stack.clone(); + lockedObjects = other.lockedObjects == EMPTY_ARRAY ? EMPTY_ARRAY : other.lockedObjects.clone(); + monitorIds = other.monitorIds == EMPTY_MONITOR_ARRAY ? EMPTY_MONITOR_ARRAY : other.monitorIds.clone(); + stackSize = other.stackSize; + rethrowException = other.rethrowException; + + assert locals.length == method.getMaxLocals(); + assert stack.length == Math.max(1, method.getMaxStackSize()); + assert lockedObjects.length == monitorIds.length; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[locals: ["); + for (int i = 0; i < locals.length; i++) { + sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id)); + } + sb.append("] stack: ["); + for (int i = 0; i < stackSize; i++) { + sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); + } + sb.append("] locks: ["); + for (int i = 0; i < lockedObjects.length; i++) { + sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); + } + sb.append("]"); + if (rethrowException) { + sb.append(" rethrowException"); + } + sb.append("]"); + return sb.toString(); + } + + public FrameState create(int bci) { + return graph.add(new FrameState(method, bci, locals, Arrays.asList(stack).subList(0, stackSize), lockedObjects, monitorIds, rethrowException, false)); + } + + public HIRFrameStateBuilder copy() { + return new HIRFrameStateBuilder(this); + } + + public boolean isCompatibleWith(HIRFrameStateBuilder other) { + assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; + assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; + + if (stackSize() != other.stackSize()) { + return false; + } + for (int i = 0; i < stackSize(); i++) { + ValueNode x = stackAt(i); + ValueNode y = other.stackAt(i); + if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) { + return false; + } + } + if (lockedObjects.length != other.lockedObjects.length) { + return false; + } + for (int i = 0; i < lockedObjects.length; i++) { + if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { + throw new BailoutException("unbalanced monitors"); + } + } + return true; + } + + public void merge(MergeNode block, HIRFrameStateBuilder other) { + assert isCompatibleWith(other); + + for (int i = 0; i < localsSize(); i++) { + storeLocal(i, merge(localAt(i), other.localAt(i), block)); + } + for (int i = 0; i < stackSize(); i++) { + storeStack(i, merge(stackAt(i), other.stackAt(i), block)); + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); + assert monitorIds[i] == other.monitorIds[i]; + } + } + + private ValueNode merge(ValueNode currentValue, ValueNode otherValue, MergeNode block) { + if (currentValue == null || currentValue.isDeleted()) { + return null; + + } else if (block.isPhiAtMerge(currentValue)) { + if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { + propagateDelete((PhiNode) currentValue); + return null; + } + ((PhiNode) currentValue).addInput(otherValue); + return currentValue; + + } else if (currentValue != otherValue) { + assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for all locals and stack slots"; + if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { + return null; + } + + PhiNode phi = graph.addWithoutUnique(new PhiNode(currentValue.stamp().unrestricted(), block)); + for (int i = 0; i < block.phiPredecessorCount(); i++) { + phi.addInput(currentValue); + } + phi.addInput(otherValue); + assert phi.valueCount() == block.phiPredecessorCount() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.phiPredecessorCount(); + return phi; + + } else { + return currentValue; + } + } + + private void propagateDelete(FloatingNode node) { + assert node instanceof PhiNode || node instanceof ProxyNode; + if (node.isDeleted()) { + return; + } + // Collect all phi functions that use this phi so that we can delete them recursively (after + // we delete ourselves to avoid circles). + List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ProxyNode.class)).snapshot(); + + // Remove the phi function from all FrameStates where it is used and then delete it. + assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + node.replaceAtUsages(null); + node.safeDelete(); + + for (FloatingNode phiUsage : propagateUsages) { + propagateDelete(phiUsage); + } + } + + public void insertLoopPhis(LoopBeginNode loopBegin) { + for (int i = 0; i < localsSize(); i++) { + storeLocal(i, createLoopPhi(loopBegin, localAt(i))); + } + for (int i = 0; i < stackSize(); i++) { + storeStack(i, createLoopPhi(loopBegin, stackAt(i))); + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]); + } + } + + public void insertLoopProxies(LoopExitNode loopExit, HIRFrameStateBuilder loopEntryState) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = localAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeLocal(i, ProxyNode.forValue(value, loopExit, graph)); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stackAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeStack(i, ProxyNode.forValue(value, loopExit, graph)); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); + } + } + } + + public void insertProxies(AbstractBeginNode begin) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = localAt(i); + if (value != null) { + Debug.log(" inserting proxy for %s", value); + storeLocal(i, ProxyNode.forValue(value, begin, graph)); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stackAt(i); + if (value != null) { + Debug.log(" inserting proxy for %s", value); + storeStack(i, ProxyNode.forValue(value, begin, graph)); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = ProxyNode.forValue(value, begin, graph); + } + } + } + + private PhiNode createLoopPhi(MergeNode block, ValueNode value) { + if (value == null) { + return null; + } + assert !block.isPhiAtMerge(value) : "phi function for this block already created"; + + PhiNode phi = graph.addWithoutUnique(new PhiNode(value.stamp().unrestricted(), block)); + phi.addInput(value); + return phi; + } + + public void cleanupDeletedPhis() { + for (int i = 0; i < localsSize(); i++) { + if (localAt(i) != null && localAt(i).isDeleted()) { + assert localAt(i) instanceof PhiNode || localAt(i) instanceof ProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i); + storeLocal(i, null); + } + } + } + + public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { + if (liveness == null) { + return; + } + if (liveIn) { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveIn(block, i)) { + locals[i] = null; + } + } + } else { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveOut(block, i)) { + locals[i] = null; + } + } + } + } + + /** + * @see BytecodeFrame#rethrowException + */ + public boolean rethrowException() { + return rethrowException; + } + + /** + * @see BytecodeFrame#rethrowException + */ + public void setRethrowException(boolean b) { + rethrowException = b; + } + + @Override + public int localsSize() { + return locals.length; + } + + @Override + public ValueNode localAt(int i) { + return locals[i]; + } + + @Override + public ValueNode stackAt(int i) { + return stack[i]; + } + + /** + * Adds a locked monitor to this frame state. + * + * @param object the object whose monitor will be locked. + */ + public void pushLock(ValueNode object, MonitorIdNode monitorId) { + assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object; + lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); + monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); + lockedObjects[lockedObjects.length - 1] = object; + monitorIds[monitorIds.length - 1] = monitorId; + assert lockedObjects.length == monitorIds.length; + } + + /** + * Removes a locked monitor from this frame state. + * + * @return the object whose monitor was removed from the locks list. + */ + public ValueNode popLock() { + try { + return lockedObjects[lockedObjects.length - 1]; + } finally { + lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); + monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); + } + } + + public MonitorIdNode peekMonitorId() { + return monitorIds[monitorIds.length - 1]; + } + + /** + * @return the current lock depth + */ + public int lockDepth() { + assert lockedObjects.length == monitorIds.length; + return lockedObjects.length; + } + + @Override + public ValueNode loadLocal(int i) { + ValueNode x = locals[i]; + assert !x.isDeleted(); + assert !isTwoSlot(x.getKind()) || locals[i + 1] == null; + assert i == 0 || locals[i - 1] == null || !isTwoSlot(locals[i - 1].getKind()); + return x; + } + + @Override + public void storeLocal(int i, ValueNode x) { + assert x == null || x.isAlive() && x.getKind() != Kind.Void && x.getKind() != Kind.Illegal : "unexpected value: " + x; + locals[i] = x; + if (x != null && isTwoSlot(x.getKind())) { + // if this is a double word, then kill i+1 + locals[i + 1] = null; + } + if (x != null && i > 0) { + ValueNode p = locals[i - 1]; + if (p != null && isTwoSlot(p.getKind())) { + // if there was a double word at i - 1, then kill it + locals[i - 1] = null; + } + } + } + + @Override + public void storeStack(int i, ValueNode x) { + assert x == null || x.isAlive() && (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; + stack[i] = x; + } + + @Override + public void push(Kind kind, ValueNode x) { + assert x.isAlive() && x.getKind() != Kind.Void && x.getKind() != Kind.Illegal; + xpush(assertKind(kind, x)); + if (isTwoSlot(kind)) { + xpush(null); + } + } + + @Override + public void xpush(ValueNode x) { + assert x == null || (x.isAlive() && x.getKind() != Kind.Void && x.getKind() != Kind.Illegal); + stack[stackSize++] = x; + } + + @Override + public void ipush(ValueNode x) { + xpush(assertInt(x)); + } + + @Override + public void fpush(ValueNode x) { + xpush(assertFloat(x)); + } + + @Override + public void apush(ValueNode x) { + xpush(assertObject(x)); + } + + @Override + public void lpush(ValueNode x) { + xpush(assertLong(x)); + xpush(null); + } + + @Override + public void dpush(ValueNode x) { + xpush(assertDouble(x)); + xpush(null); + } + + @Override + public void pushReturn(Kind kind, ValueNode x) { + if (kind != Kind.Void) { + push(kind.getStackKind(), x); + } + } + + @Override + public ValueNode pop(Kind kind) { + assert kind != Kind.Void; + if (isTwoSlot(kind)) { + xpop(); + } + return assertKind(kind, xpop()); + } + + @Override + public ValueNode xpop() { + ValueNode result = stack[--stackSize]; + assert result == null || !result.isDeleted(); + return result; + } + + @Override + public ValueNode ipop() { + return assertInt(xpop()); + } + + @Override + public ValueNode fpop() { + return assertFloat(xpop()); + } + + @Override + public ValueNode apop() { + return assertObject(xpop()); + } + + @Override + public ValueNode lpop() { + assertHigh(xpop()); + return assertLong(xpop()); + } + + @Override + public ValueNode dpop() { + assertHigh(xpop()); + return assertDouble(xpop()); + } + + @Override + public ValueNode[] popArguments(int slotSize, int argSize) { + int base = stackSize - slotSize; + ValueNode[] r = new ValueNode[argSize]; + int argIndex = 0; + int stackindex = 0; + while (stackindex < slotSize) { + ValueNode element = stack[base + stackindex]; + assert element != null; + r[argIndex++] = element; + stackindex += stackSlots(element.getKind()); + } + stackSize = base; + return r; + } + + @Override + public ValueNode peek(int argumentNumber) { + int idx = stackSize() - 1; + for (int i = 0; i < argumentNumber; i++) { + if (stackAt(idx) == null) { + idx--; + assert isTwoSlot(stackAt(idx).getKind()); + } + idx--; + } + return stackAt(idx); + } + + public boolean contains(ValueNode value) { + for (int i = 0; i < localsSize(); i++) { + if (localAt(i) == value) { + return true; + } + } + for (int i = 0; i < stackSize(); i++) { + if (stackAt(i) == value) { + return true; + } + } + assert lockedObjects.length == monitorIds.length; + for (int i = 0; i < lockedObjects.length; i++) { + if (lockedObjects[i] == value || monitorIds[i] == value) { + return true; + } + } + return false; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_getfield1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/BC_getfield1.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + */ +package com.oracle.graal.jtt.except; + +import com.oracle.graal.jtt.*; + +import org.junit.*; + +public class BC_getfield1 extends JTTTest { + + private int field = 13; + + public static void test(BC_getfield1 arg) { + @SuppressWarnings("unused") + int i = arg.field; + } + + @Test + public void run0() throws Throwable { + runTest("test", (Object) null); + } + + @Test + public void run1() throws Throwable { + // tests that the null check isn't removed along with the read + runTest(EMPTY, true, true, "test", (Object) null); + } + + @Test + public void run2() throws Throwable { + runTest("test", new BC_getfield1()); + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java Sun Mar 30 16:08:33 2014 +0200 @@ -46,19 +46,18 @@ return sum; } - // CheckStyle: stop system..print check private static void doPrint(int n) { + PrintStream out = System.out; for (int i = 0; i < n; i++) { - System.out.print('x'); + out.print('x'); } } public static void main(String[] args) throws Exception { - System.out.println(test(10000)); + PrintStream out = System.out; + out.println(test(10000)); } - // CheckStyle: resume system..print check - @LongTest public void run0() throws Throwable { runTest("test", 10000); diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Sun Mar 30 16:08:33 2014 +0200 @@ -49,6 +49,7 @@ I2F, I2D, L2F, L2D, MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L, + MOV_B2UI, MOV_B2UL, // Zero extending byte loads /* * Converts a float/double to an int/long. The result of the conversion does not comply with Java semantics @@ -102,6 +103,32 @@ } /** + * Unary operation with separate memory source and destination operand. + */ + public static class Unary2MemoryOp extends AMD64LIRInstruction { + + @Opcode private final AMD64Arithmetic opcode; + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE}) protected AMD64AddressValue x; + @State protected LIRFrameState state; + + public Unary2MemoryOp(AMD64Arithmetic opcode, AllocatableValue result, AMD64AddressValue x, LIRFrameState state) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + emit(crb, masm, opcode, result, x, null); + } + } + + /** * Binary operation with two operands. The first source operand is combined with the * destination. The second source operand may be a stack slot. */ @@ -135,6 +162,45 @@ /** * Binary operation with two operands. The first source operand is combined with the + * destination. The second source operand may be a stack slot. + */ + public static class BinaryMemory extends AMD64LIRInstruction { + + @Opcode private final AMD64Arithmetic opcode; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + protected final Kind kind; + @Alive({COMPOSITE}) protected AMD64AddressValue location; + @State protected LIRFrameState state; + + public BinaryMemory(AMD64Arithmetic opcode, Kind kind, AllocatableValue result, AllocatableValue x, AMD64AddressValue location, LIRFrameState state) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.location = location; + this.kind = kind; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + emit(crb, masm, opcode, result, location, null); + } + + @Override + public void verify() { + super.verify(); + assert differentRegisters(result, location) || sameRegister(x, location); + // verifyKind(opcode, result, x, location); + } + } + + /** + * Binary operation with two operands. The first source operand is combined with the * destination. The second source operand must be a register. */ public static class BinaryRegReg extends AMD64LIRInstruction { @@ -688,7 +754,8 @@ default: throw GraalInternalError.shouldNotReachHere(); } - } else { + } else if (isStackSlot(src)) { + switch (opcode) { case IADD: masm.addl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); @@ -819,6 +886,143 @@ default: throw GraalInternalError.shouldNotReachHere(); } + } else { + switch (opcode) { + case IADD: + masm.addl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case ISUB: + masm.subl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case IAND: + masm.andl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case IMUL: + masm.imull(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case IOR: + masm.orl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case IXOR: + masm.xorl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + + case LADD: + masm.addq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case LSUB: + masm.subq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case LMUL: + masm.imulq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case LAND: + masm.andq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case LOR: + masm.orq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case LXOR: + masm.xorq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + + case FADD: + masm.addss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case FSUB: + masm.subss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case FMUL: + masm.mulss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case FDIV: + masm.divss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + + case DADD: + masm.addsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case DSUB: + masm.subsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case DMUL: + masm.mulsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case DDIV: + masm.divsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + + case SQRT: + masm.sqrtsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + + case B2I: + masm.movsbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case S2I: + masm.movswl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case B2L: + masm.movsbq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case S2L: + masm.movswq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case I2L: + masm.movslq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case F2D: + masm.cvtss2sd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case D2F: + masm.cvtsd2ss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case I2F: + masm.cvtsi2ssl(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case I2D: + masm.cvtsi2sdl(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case L2F: + masm.cvtsi2ssq(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case L2D: + masm.cvtsi2sdq(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case F2I: + masm.cvttss2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case D2I: + masm.cvttsd2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case F2L: + masm.cvttss2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case D2L: + masm.cvttsd2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case MOV_I2F: + masm.movss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case MOV_L2D: + masm.movsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case MOV_F2I: + masm.movl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case MOV_D2L: + masm.movq(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case MOV_B2UI: + masm.movzbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + case MOV_B2UL: + masm.movzbl(asLongReg(dst), ((AMD64AddressValue) src).toAddress()); + break; + + default: + throw GraalInternalError.shouldNotReachHere(); + } } if (info != null) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Sun Mar 30 16:08:33 2014 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; -// @formatter:off public enum AMD64Compare { ICMP, LCMP, ACMP, FCMP, DCMP; @@ -54,57 +53,152 @@ @Override protected void verify() { super.verify(); - assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) - || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) - || (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) - || (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) - || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double); + assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) || + (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) || + (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double); + } + } + + public static class CompareMemoryOp extends AMD64LIRInstruction { + @Opcode private final AMD64Compare opcode; + @Use({REG, COMPOSITE}) protected Value x; + @Use({CONST, COMPOSITE}) protected Value y; + @State protected LIRFrameState state; + + /** + * Compare memory, constant or register, memory. + */ + public CompareMemoryOp(AMD64Compare opcode, Value x, Value y, LIRFrameState state) { + assert (x instanceof AMD64AddressValue && y instanceof Constant) || (x instanceof Variable && y instanceof AMD64AddressValue); + this.opcode = opcode; + this.x = x; + this.y = y; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + emit(crb, masm, opcode, x, y); + } + + @Override + protected void verify() { + super.verify(); + assert (x instanceof AMD64AddressValue && y instanceof Constant) || (x instanceof Variable && y instanceof AMD64AddressValue); } } public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Compare opcode, Value x, Value y) { - if (isRegister(y)) { + if (isRegister(x) && isRegister(y)) { switch (opcode) { - case ICMP: masm.cmpl(asIntReg(x), asIntReg(y)); break; - case LCMP: masm.cmpq(asLongReg(x), asLongReg(y)); break; - case ACMP: masm.cmpptr(asObjectReg(x), asObjectReg(y)); break; - case FCMP: masm.ucomiss(asFloatReg(x), asFloatReg(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), asDoubleReg(y)); break; - default: throw GraalInternalError.shouldNotReachHere(); + case ICMP: + masm.cmpl(asIntReg(x), asIntReg(y)); + break; + case LCMP: + masm.cmpq(asLongReg(x), asLongReg(y)); + break; + case ACMP: + masm.cmpptr(asObjectReg(x), asObjectReg(y)); + break; + case FCMP: + masm.ucomiss(asFloatReg(x), asFloatReg(y)); + break; + case DCMP: + masm.ucomisd(asDoubleReg(x), asDoubleReg(y)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } - } else if (isConstant(y)) { + } else if (isRegister(x) && isConstant(y)) { boolean isZero = ((Constant) y).isDefaultForKind(); switch (opcode) { - case ICMP: if (isZero) { - masm.testl(asIntReg(x), asIntReg(x)); - } else { - masm.cmpl(asIntReg(x), crb.asIntConst(y)); - } - break; - case LCMP: if (isZero) { - masm.testq(asLongReg(x), asLongReg(x)); - } else { - masm.cmpq(asLongReg(x), crb.asIntConst(y)); - } - break; + case ICMP: + if (isZero) { + masm.testl(asIntReg(x), asIntReg(x)); + } else { + masm.cmpl(asIntReg(x), crb.asIntConst(y)); + } + break; + case LCMP: + if (isZero) { + masm.testq(asLongReg(x), asLongReg(x)); + } else { + masm.cmpq(asLongReg(x), crb.asIntConst(y)); + } + break; case ACMP: if (isZero) { - masm.testq(asObjectReg(x), asObjectReg(x)); break; + masm.testq(asObjectReg(x), asObjectReg(x)); + break; } else { throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons"); } - case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y)); break; - default: throw GraalInternalError.shouldNotReachHere(); + case FCMP: + masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y)); + break; + case DCMP: + masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } - } else { + } else if (isRegister(x) && isStackSlot(y)) { + switch (opcode) { + case ICMP: + masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y)); + break; + case LCMP: + masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y)); + break; + case ACMP: + masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y)); + break; + case FCMP: + masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y)); + break; + case DCMP: + masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isRegister(x) && y instanceof AMD64AddressValue) { switch (opcode) { - case ICMP: masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y)); break; - case LCMP: masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y)); break; - case ACMP: masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y)); break; - case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y)); break; - default: throw GraalInternalError.shouldNotReachHere(); + case ICMP: + masm.cmpl(asIntReg(x), ((AMD64AddressValue) y).toAddress()); + break; + case LCMP: + masm.cmpq(asLongReg(x), ((AMD64AddressValue) y).toAddress()); + break; + case ACMP: + masm.cmpptr(asObjectReg(x), ((AMD64AddressValue) y).toAddress()); + break; + case FCMP: + masm.ucomiss(asFloatReg(x), ((AMD64AddressValue) y).toAddress()); + break; + case DCMP: + masm.ucomisd(asDoubleReg(x), ((AMD64AddressValue) y).toAddress()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else if (x instanceof AMD64AddressValue && isConstant(y)) { + switch (opcode) { + case ICMP: + masm.cmpl(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y)); + break; + case LCMP: + if (crb.asLongConst(y) == (int) crb.asLongConst(y)) { + masm.cmpq(((AMD64AddressValue) x).toAddress(), (int) crb.asLongConst(y)); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); } } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CompilationResult.RawData; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; @@ -171,6 +172,38 @@ } } + public static class ZeroExtendLoadOp extends MemOp { + + @Def({REG}) protected AllocatableValue result; + + public ZeroExtendLoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) { + super(kind, address, state); + this.result = result; + } + + @Override + public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + switch (kind) { + case Boolean: + case Byte: + masm.movzbl(asRegister(result), address.toAddress()); + break; + case Char: + case Short: + masm.movzwl(asRegister(result), address.toAddress()); + break; + case Int: + masm.movl(asRegister(result), address.toAddress()); + break; + case Long: + masm.movq(asRegister(result), address.toAddress()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + public static class StoreOp extends MemOp { @Use({REG}) protected AllocatableValue input; @@ -277,6 +310,23 @@ } } + public static class LeaDataOp extends AMD64LIRInstruction { + + @Def({REG}) protected AllocatableValue result; + private final byte[] data; + + public LeaDataOp(AllocatableValue result, byte[] data) { + this.result = result; + this.data = data; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + RawData rawData = new RawData(data, 16); + masm.leaq(asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(rawData)); + } + } + public static class StackLeaOp extends AMD64LIRInstruction { @Def({REG}) protected AllocatableValue result; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64TestMemoryOp extends AMD64LIRInstruction { + + @Use({COMPOSITE}) protected AMD64AddressValue x; + @Use({REG, CONST}) protected Value y; + @State protected LIRFrameState state; + + public AMD64TestMemoryOp(AMD64AddressValue x, Value y, LIRFrameState state) { + this.x = x; + this.y = y; + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + emit(crb, masm, x, y); + } + + @Override + protected void verify() { + super.verify(); + // Can't check the kind of an address so just check the other input + assert (x.getKind() == Kind.Int || x.getKind() == Kind.Long) : x + " " + y; + } + + public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value x, Value y) { + if (isRegister(y)) { + switch (y.getKind()) { + case Int: + masm.testl(asIntReg(y), ((AMD64AddressValue) x).toAddress()); + break; + case Long: + masm.testq(asLongReg(y), ((AMD64AddressValue) x).toAddress()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(y)) { + switch (y.getKind()) { + case Int: + masm.testl(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y)); + break; + case Long: + masm.testq(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Sun Mar 30 16:08:33 2014 +0200 @@ -34,6 +34,11 @@ import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.calc.*; +import static com.oracle.graal.api.code.ValueUtil.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.hsail.HSAIL; + /** * Implementation of control flow instructions. */ @@ -96,11 +101,11 @@ protected void conditionalJump(int index, Condition condition, Label target) { switch (key.getKind()) { case Int: + case Long: // Generate cascading compare and branches for each case. masm.emitCompare(key, keyConstants[index], HSAILCompare.conditionToString(condition), false, false); masm.cbr(masm.nameOf(target)); break; - case Long: case Object: default: throw new GraalInternalError("switch only supported for int"); @@ -126,6 +131,100 @@ } } + /*** + * The ALIVE annotation is so we can get a scratch32 register that does not clobber + * actionAndReason. + */ + public static class DeoptimizeOp extends ReturnOp { + + @Alive({REG, CONST}) protected Value actionAndReason; + @State protected LIRFrameState frameState; + protected MetaAccessProvider metaAccessProvider; + protected String emitName; + protected int codeBufferPos = -1; + protected int dregOopMap = 0; + + public DeoptimizeOp(Value actionAndReason, LIRFrameState frameState, String emitName, MetaAccessProvider metaAccessProvider) { + super(Value.ILLEGAL); // return with no ret value + this.actionAndReason = actionAndReason; + this.frameState = frameState; + this.emitName = emitName; + this.metaAccessProvider = metaAccessProvider; + } + + @Override + public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { + String reasonString; + if (isConstant(actionAndReason)) { + DeoptimizationReason reason = metaAccessProvider.decodeDeoptReason((Constant) actionAndReason); + reasonString = reason.toString(); + } else { + reasonString = "Variable Reason"; + } + + masm.emitComment("// " + emitName + ", Deoptimization for " + reasonString); + + if (frameState == null) { + masm.emitComment("// frameState == null"); + // and emit the return + super.emitCode(crb, masm); + return; + } + // get a unique codeBuffer position + // when we save our state, we will save this as well (it can be used as a key to get the + // debugInfo) + codeBufferPos = masm.position(); + + // get the bitmap of $d regs that contain references + ReferenceMap referenceMap = frameState.debugInfo().getReferenceMap(); + for (int dreg = HSAIL.d0.number; dreg <= HSAIL.d15.number; dreg++) { + if (referenceMap.getRegister(dreg) == Kind.Object) { + dregOopMap |= 1 << (dreg - HSAIL.d0.number); + } + } + + // here we will by convention use some never-allocated registers to pass to the epilogue + // deopt code + // todo: define these in HSAIL.java + // we need to pass the actionAndReason and the codeBufferPos + + AllocatableValue actionAndReasonReg = HSAIL.s32.asValue(Kind.Int); + AllocatableValue codeBufferOffsetReg = HSAIL.s33.asValue(Kind.Int); + AllocatableValue dregOopMapReg = HSAIL.s39.asValue(Kind.Int); + masm.emitMov(actionAndReasonReg, actionAndReason); + masm.emitMov(codeBufferOffsetReg, Constant.forInt(codeBufferPos)); + masm.emitMov(dregOopMapReg, Constant.forInt(dregOopMap)); + masm.emitJumpToLabelName(masm.getDeoptLabelName()); + + // now record the debuginfo + crb.recordInfopoint(codeBufferPos, frameState, InfopointReason.IMPLICIT_EXCEPTION); + } + + public LIRFrameState getFrameState() { + return frameState; + } + + public int getCodeBufferPos() { + return codeBufferPos; + } + } + + public static class UnwindOp extends ReturnOp { + + protected String commentMessage; + + public UnwindOp(String commentMessage) { + super(Value.ILLEGAL); // return with no ret value + this.commentMessage = commentMessage; + } + + @Override + public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { + masm.emitComment("// " + commentMessage); + super.emitCode(crb, masm); + } + } + public static class ForeignCallNoArgOp extends HSAILLIRInstruction { @Def({REG}) protected Value out; @@ -224,7 +323,7 @@ @Override public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { HSAILCompare.emit(crb, masm, condition, left, right, right, false); - cmove(crb, masm, result, false, trueValue, falseValue); + cmove(masm, result, trueValue, falseValue); } } @@ -240,12 +339,11 @@ @Override public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { HSAILCompare.emit(crb, masm, condition, left, right, right, unorderedIsTrue); - cmove(crb, masm, result, false, trueValue, falseValue); + cmove(masm, result, trueValue, falseValue); } } - @SuppressWarnings("unused") - private static void cmove(CompilationResultBuilder crb, HSAILAssembler masm, Value result, boolean unorderedIsTrue, Value trueValue, Value falseValue) { + private static void cmove(HSAILAssembler masm, Value result, Value trueValue, Value falseValue) { // Check that we don't overwrite an input operand before it is used. assert (result.getKind() == trueValue.getKind() && result.getKind() == falseValue.getKind()); int width; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,13 +23,32 @@ package com.oracle.graal.lir.sparc; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import static com.oracle.graal.sparc.SPARC.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCAssembler.Add; +import com.oracle.graal.asm.sparc.SPARCAssembler.Lddf; +import com.oracle.graal.asm.sparc.SPARCAssembler.Ldf; +import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsb; +import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsh; +import com.oracle.graal.asm.sparc.SPARCAssembler.Ldsw; +import com.oracle.graal.asm.sparc.SPARCAssembler.Lduh; +import com.oracle.graal.asm.sparc.SPARCAssembler.Ldx; +import com.oracle.graal.asm.sparc.SPARCAssembler.Membar; +import com.oracle.graal.asm.sparc.SPARCAssembler.Rdpc; +import com.oracle.graal.asm.sparc.SPARCAssembler.Stb; +import com.oracle.graal.asm.sparc.SPARCAssembler.Sth; +import com.oracle.graal.asm.sparc.SPARCAssembler.Stw; +import com.oracle.graal.asm.sparc.SPARCAssembler.Stx; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cas; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Casx; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Clr; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setuw; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java Sun Mar 30 16:08:33 2014 +0200 @@ -37,9 +37,8 @@ /** * Performs control flow optimizations on the given LIR graph. */ - public static void optimize(LIR lir) { - List blocks = lir.codeEmittingOrder(); - ControlFlowOptimizer.deleteEmptyBlocks(lir, blocks); + public static > void optimize(LIR lir, List codeEmittingOrder) { + ControlFlowOptimizer.deleteEmptyBlocks(lir, codeEmittingOrder); } private ControlFlowOptimizer() { @@ -54,41 +53,41 @@ * @param block the block checked for deletion * @return whether the block can be deleted */ - private static boolean canDeleteBlock(LIR lir, Block block) { - if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getFirstSuccessor() == block) { + private static boolean canDeleteBlock(LIR lir, AbstractBlock block) { + if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getSuccessors().iterator().next() == block) { return false; } - List instructions = lir.lir(block); + List instructions = lir.getLIRforBlock(block); assert instructions.size() >= 2 : "block must have label and branch"; assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label"; assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch"; - assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.lir(block.getFirstSuccessor()).get(0)).getLabel() : "branch target must be the successor"; + assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.getLIRforBlock(block.getSuccessors().iterator().next()).get(0)).getLabel() : "branch target must be the successor"; // Block must have exactly one successor. return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry(); } - private static void alignBlock(LIR lir, Block block) { + private static void alignBlock(LIR lir, AbstractBlock block) { if (!block.isAligned()) { block.setAlign(true); - List instructions = lir.lir(block); + List instructions = lir.getLIRforBlock(block); assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label"; StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0); instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true)); } } - private static void deleteEmptyBlocks(LIR lir, List blocks) { + private static > void deleteEmptyBlocks(LIR lir, List blocks) { assert verifyBlocks(lir, blocks); - Iterator iterator = blocks.iterator(); + Iterator iterator = blocks.iterator(); while (iterator.hasNext()) { - Block block = iterator.next(); + T block = iterator.next(); if (canDeleteBlock(lir, block)) { // adjust successor and predecessor lists - Block other = block.getFirstSuccessor(); - for (Block pred : block.getPredecessors()) { + T other = block.getSuccessors().iterator().next(); + for (AbstractBlock pred : block.getPredecessors()) { Collections.replaceAll(pred.getSuccessors(), block, other); } for (int i = 0; i < other.getPredecessorCount(); i++) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Sun Mar 30 16:08:33 2014 +0200 @@ -53,10 +53,10 @@ public static void optimize(LIR ir) { EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(ir); - List blockList = ir.linearScanOrder(); + List> blockList = ir.linearScanOrder(); // ignore the first block in the list (index 0 is not processed) for (int i = blockList.size() - 1; i >= 1; i--) { - Block block = blockList.get(i); + AbstractBlock block = blockList.get(i); if (block.getPredecessorCount() > 1) { optimizer.optimizeMovesAtBlockEnd(block); @@ -103,8 +103,8 @@ * Moves the longest {@linkplain #same common} subsequence at the end all predecessors of * {@code block} to the start of {@code block}. */ - private void optimizeMovesAtBlockEnd(Block block) { - for (Block pred : block.getPredecessors()) { + private void optimizeMovesAtBlockEnd(AbstractBlock block) { + for (AbstractBlock pred : block.getPredecessors()) { if (pred == block) { // currently we can't handle this correctly. return; @@ -118,10 +118,10 @@ assert numPreds > 1 : "do not call otherwise"; // setup a list with the LIR instructions of all predecessors - for (Block pred : block.getPredecessors()) { + for (AbstractBlock pred : block.getPredecessors()) { assert pred != null; - assert ir.lir(pred) != null; - List predInstructions = ir.lir(pred); + assert ir.getLIRforBlock(pred) != null; + List predInstructions = ir.getLIRforBlock(pred); if (pred.getSuccessorCount() != 1) { // this can happen with switch-statements where multiple edges are between @@ -129,7 +129,7 @@ return; } - assert pred.getFirstSuccessor() == block : "invalid control flow"; + assert pred.getSuccessors().iterator().next() == block : "invalid control flow"; assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump"; if (predInstructions.get(predInstructions.size() - 1).hasState()) { @@ -158,7 +158,7 @@ } // insert the instruction at the beginning of the current block - ir.lir(block).add(1, op); + ir.getLIRforBlock(block).add(1, op); // delete the instruction at the end of all predecessors for (int i = 0; i < numPreds; i++) { @@ -173,12 +173,12 @@ * {@code block} to the end of {@code block} just prior to the branch instruction ending * {@code block}. */ - private void optimizeMovesAtBlockBegin(Block block) { + private void optimizeMovesAtBlockBegin(AbstractBlock block) { edgeInstructionSeqences.clear(); int numSux = block.getSuccessorCount(); - List instructions = ir.lir(block); + List instructions = ir.getLIRforBlock(block); assert numSux == 2 : "method should not be called otherwise"; @@ -203,8 +203,8 @@ int insertIdx = instructions.size() - 1; // setup a list with the lir-instructions of all successors - for (Block sux : block.getSuccessors()) { - List suxInstructions = ir.lir(sux); + for (AbstractBlock sux : block.getSuccessors()) { + List suxInstructions = ir.getLIRforBlock(sux); assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; @@ -213,7 +213,7 @@ // the same blocks. return; } - assert sux.getFirstPredecessor() == block : "invalid control flow"; + assert sux.getPredecessors().iterator().next() == block : "invalid control flow"; // ignore the label at the beginning of the block List seq = suxInstructions.subList(1, suxInstructions.size()); @@ -238,7 +238,7 @@ } // insert instruction at end of current block - ir.lir(block).add(insertIdx, op); + ir.getLIRforBlock(block).add(insertIdx, op); insertIdx++; // delete the instructions at the beginning of all successors diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Sun Mar 30 16:08:33 2014 +0200 @@ -35,17 +35,17 @@ */ public class LIR { - private final ControlFlowGraph cfg; + private final AbstractControlFlowGraph cfg; /** * The linear-scan ordered list of blocks. */ - private final List linearScanOrder; + private final List> linearScanOrder; /** * The order in which the code is emitted. */ - private final List codeEmittingOrder; + private final List> codeEmittingOrder; private int firstVariableNumber; @@ -65,14 +65,14 @@ /** * Creates a new LIR instance for the specified compilation. */ - public LIR(ControlFlowGraph cfg, List linearScanOrder, List codeEmittingOrder) { + public LIR(AbstractControlFlowGraph cfg, List> linearScanOrder, List> codeEmittingOrder) { this.cfg = cfg; this.codeEmittingOrder = codeEmittingOrder; this.linearScanOrder = linearScanOrder; this.lirInstructions = new BlockMap<>(cfg); } - public ControlFlowGraph getControlFlowGraph() { + public AbstractControlFlowGraph getControlFlowGraph() { return cfg; } @@ -80,8 +80,8 @@ * Determines if any instruction in the LIR has debug info associated with it. */ public boolean hasDebugInfo() { - for (Block b : linearScanOrder()) { - for (LIRInstruction op : lir(b)) { + for (AbstractBlock b : linearScanOrder()) { + for (LIRInstruction op : getLIRforBlock(b)) { if (op.hasState()) { return true; } @@ -94,12 +94,12 @@ return spillMoveFactory; } - public List lir(AbstractBlock block) { + public List getLIRforBlock(AbstractBlock block) { return lirInstructions.get(block); } - public void setLir(Block block, List list) { - assert lir(block) == null : "lir instruction list should only be initialized once"; + public void setLIRforBlock(AbstractBlock block, List list) { + assert getLIRforBlock(block) == null : "lir instruction list should only be initialized once"; lirInstructions.put(block, list); } @@ -108,11 +108,11 @@ * * @return the blocks in linear scan order */ - public List linearScanOrder() { + public List> linearScanOrder() { return linearScanOrder; } - public List codeEmittingOrder() { + public List> codeEmittingOrder() { return codeEmittingOrder; } @@ -169,8 +169,8 @@ */ public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 3; - public static boolean verifyBlock(LIR lir, Block block) { - List ops = lir.lir(block); + public static boolean verifyBlock(LIR lir, AbstractBlock block) { + List ops = lir.getLIRforBlock(block); if (ops.size() == 0) { return false; } @@ -193,12 +193,12 @@ return true; } - public static boolean verifyBlocks(LIR lir, List blocks) { - for (Block block : blocks) { - for (Block sux : block.getSuccessors()) { + public static boolean verifyBlocks(LIR lir, List> blocks) { + for (AbstractBlock block : blocks) { + for (AbstractBlock sux : block.getSuccessors()) { assert blocks.contains(sux) : "missing successor from: " + block + "to: " + sux; } - for (Block pred : block.getPredecessors()) { + for (AbstractBlock pred : block.getPredecessors()) { assert blocks.contains(pred) : "missing predecessor from: " + block + "to: " + pred; } if (!verifyBlock(lir, block)) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Sun Mar 30 16:08:33 2014 +0200 @@ -46,11 +46,11 @@ private final BitSet[] blockLiveOut; private final Object[] variableDefinitions; - private BitSet liveOutFor(Block block) { + private BitSet liveOutFor(AbstractBlock block) { return blockLiveOut[block.getId()]; } - private void setLiveOutFor(Block block, BitSet liveOut) { + private void setLiveOutFor(AbstractBlock block, BitSet liveOut) { blockLiveOut[block.getId()] = liveOut; } @@ -98,7 +98,7 @@ private BitSet curVariablesLive; private Value[] curRegistersLive; - private Block curBlock; + private AbstractBlock curBlock; private Object curInstruction; private BitSet curRegistersDefined; @@ -120,7 +120,7 @@ int maxRegisterNum = maxRegisterNum(); curRegistersDefined = new BitSet(); - for (Block block : lir.linearScanOrder()) { + for (AbstractBlock block : lir.linearScanOrder()) { curBlock = block; curVariablesLive = new BitSet(); curRegistersLive = new Value[maxRegisterNum]; @@ -129,14 +129,14 @@ curVariablesLive.or(liveOutFor(block.getDominator())); } - assert lir.lir(block).get(0) instanceof StandardOp.LabelOp : "block must start with label"; + assert lir.getLIRforBlock(block).get(0) instanceof StandardOp.LabelOp : "block must start with label"; if (block.getSuccessorCount() > 0) { - LIRInstruction last = lir.lir(block).get(lir.lir(block).size() - 1); + LIRInstruction last = lir.getLIRforBlock(block).get(lir.getLIRforBlock(block).size() - 1); assert last instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; } - for (LIRInstruction op : lir.lir(block)) { + for (LIRInstruction op : lir.getLIRforBlock(block)) { curInstruction = op; op.forEachInput(useProc); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Sun Mar 30 16:08:33 2014 +0200 @@ -73,7 +73,7 @@ } public Label label() { - return ((StandardOp.LabelOp) lir.lir(getTargetBlock()).get(0)).getLabel(); + return ((StandardOp.LabelOp) lir.getLIRforBlock(getTargetBlock()).get(0)).getLabel(); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java Sun Mar 30 16:08:33 2014 +0200 @@ -31,16 +31,16 @@ public final class NullCheckOptimizer { public static void optimize(LIR ir, int implicitNullCheckLimit) { - List blocks = ir.codeEmittingOrder(); + List> blocks = ir.codeEmittingOrder(); NullCheckOptimizer.foldNullChecks(ir, blocks, implicitNullCheckLimit); } private NullCheckOptimizer() { } - private static void foldNullChecks(LIR ir, List blocks, int implicitNullCheckLimit) { - for (Block block : blocks) { - List list = ir.lir(block); + private static void foldNullChecks(LIR ir, List> blocks, int implicitNullCheckLimit) { + for (AbstractBlock block : blocks) { + List list = ir.getLIRforBlock(block); if (!list.isEmpty()) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java Sun Mar 30 16:08:33 2014 +0200 @@ -50,7 +50,7 @@ * instruction. Note that because instructions can have multiple outputs it is not possible to * use the instruction id for value numbering. In addition, the result of merging at block * entries (= phi values) get unique value numbers. - * + * * The value numbers also contain information if it is an object kind value or not: if the * number is negative it is an object kind value. */ @@ -79,7 +79,7 @@ int entryValueNum; } - Map blockData = new HashMap<>(); + Map, BlockData> blockData = new HashMap<>(); Register[] callerSaveRegs; @@ -134,7 +134,7 @@ private void initBlockData(LIR lir) { - List blocks = lir.linearScanOrder(); + List> blocks = lir.linearScanOrder(); numRegs = 0; int maxStackLocations = COMPLEXITY_LIMIT / blocks.size(); @@ -143,8 +143,8 @@ * Search for relevant locations which can be optimized. These are register or stack slots * which occur as destinations of move instructions. */ - for (Block block : blocks) { - List instructions = lir.lir(block); + for (AbstractBlock block : blocks) { + List instructions = lir.getLIRforBlock(block); for (LIRInstruction op : instructions) { if (isEligibleMove(op)) { Value dest = ((MoveOp) op).getResult(); @@ -168,7 +168,7 @@ */ int numLocations = numRegs + stackIndices.size(); Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size()); - for (Block block : blocks) { + for (AbstractBlock block : blocks) { BlockData data = new BlockData(numLocations); blockData.put(block, data); } @@ -176,100 +176,101 @@ /** * Calculates the entry and exit states for all basic blocks. - * + * * @return Returns true on success and false if the the control flow is too complex. */ private boolean solveDataFlow(LIR lir) { - Indent indent = Debug.logAndIndent("solve data flow"); + try (Indent indent = Debug.logAndIndent("solve data flow")) { - List blocks = lir.linearScanOrder(); + List> blocks = lir.linearScanOrder(); - int numIter = 0; + int numIter = 0; - /* - * Iterate until there are no more changes. - */ - int currentValueNum = 1; - boolean firstRound = true; - boolean changed; - do { - changed = false; - Indent indent2 = indent.logAndIndent("new iteration"); + /* + * Iterate until there are no more changes. + */ + int currentValueNum = 1; + boolean firstRound = true; + boolean changed; + do { + changed = false; + try (Indent indent2 = Debug.logAndIndent("new iteration")) { + + for (AbstractBlock block : blocks) { - for (Block block : blocks) { + BlockData data = blockData.get(block); + /* + * Initialize the number for global value numbering for this block. It is + * essential that the starting number for a block is consistent at all + * iterations and also in eliminateMoves(). + */ + if (firstRound) { + data.entryValueNum = currentValueNum; + } + int valueNum = data.entryValueNum; + assert valueNum > 0; + boolean newState = false; - BlockData data = blockData.get(block); - /* - * Initialize the number for global value numbering for this block. It is essential - * that the starting number for a block is consistent at all iterations and also in - * eliminateMoves(). - */ - if (firstRound) { - data.entryValueNum = currentValueNum; - } - int valueNum = data.entryValueNum; - assert valueNum > 0; - boolean newState = false; + if (block == blocks.get(0) || block.isExceptionEntry()) { + /* + * The entry block has undefined values. And also exception handler + * blocks: the LinearScan can insert moves at the end of an exception + * handler predecessor block (after the invoke, which throws the + * exception), and in reality such moves are not in the control flow in + * case of an exception. So we assume a save default for exception + * handler blocks. + */ + Debug.log("kill all values at entry of block %d", block.getId()); + clearValues(data.entryState, valueNum); + } else { + /* + * Merge the states of predecessor blocks + */ + for (AbstractBlock predecessor : block.getPredecessors()) { + BlockData predData = blockData.get(predecessor); + newState |= mergeState(data.entryState, predData.exitState, valueNum); + } + } + // Advance by the value numbers which are "consumed" by + // clearValues and mergeState + valueNum += data.entryState.length; - if (block == blocks.get(0) || block.isExceptionEntry()) { + if (newState || firstRound) { + try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) { + + /* + * Derive the exit state from the entry state by iterating through + * all instructions of the block. + */ + int[] iterState = data.exitState; + copyState(iterState, data.entryState); + List instructions = lir.getLIRforBlock(block); + + for (LIRInstruction op : instructions) { + valueNum = updateState(iterState, op, valueNum); + } + changed = true; + } + } + if (firstRound) { + currentValueNum = valueNum; + } + } + firstRound = false; + } + numIter++; + + if (numIter > 5) { /* - * The entry block has undefined values. And also exception handler blocks: the - * LinearScan can insert moves at the end of an exception handler predecessor - * block (after the invoke, which throws the exception), and in reality such - * moves are not in the control flow in case of an exception. So we assume a - * save default for exception handler blocks. - */ - indent2.log("kill all values at entry of block %d", block.getId()); - clearValues(data.entryState, valueNum); - } else { - /* - * Merge the states of predecessor blocks + * This is _very_ seldom. */ - for (Block predecessor : block.getPredecessors()) { - BlockData predData = blockData.get(predecessor); - newState |= mergeState(data.entryState, predData.exitState, valueNum); - } + return false; } - // Advance by the value numbers which are "consumed" by clearValues and mergeState - valueNum += data.entryState.length; - - if (newState || firstRound) { - - Indent indent3 = indent2.logAndIndent("update block %d", block.getId()); - - /* - * Derive the exit state from the entry state by iterating through all - * instructions of the block. - */ - int[] iterState = data.exitState; - copyState(iterState, data.entryState); - List instructions = lir.lir(block); - for (LIRInstruction op : instructions) { - valueNum = updateState(iterState, op, valueNum); - } - changed = true; - indent3.outdent(); - } - if (firstRound) { - currentValueNum = valueNum; - } - } - firstRound = false; - indent2.outdent(); - numIter++; + } while (changed); - if (numIter > 5) { - /* - * This is _very_ seldom. - */ - return false; - } - - } while (changed); - - indent.outdent(); + } return true; } @@ -279,47 +280,48 @@ */ private void eliminateMoves(LIR lir) { - Indent indent = Debug.logAndIndent("eliminate moves"); + try (Indent indent = Debug.logAndIndent("eliminate moves")) { + + List> blocks = lir.linearScanOrder(); - List blocks = lir.linearScanOrder(); + for (AbstractBlock block : blocks) { - for (Block block : blocks) { + try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) { - Indent indent2 = indent.logAndIndent("eliminate moves in block %d", block.getId()); + List instructions = lir.getLIRforBlock(block); + BlockData data = blockData.get(block); + boolean hasDead = false; - List instructions = lir.lir(block); - BlockData data = blockData.get(block); - boolean hasDead = false; + // Reuse the entry state for iteration, we don't need it later. + int[] iterState = data.entryState; - // Reuse the entry state for iteration, we don't need it later. - int[] iterState = data.entryState; + // Add the values which are "consumed" by clearValues and + // mergeState in solveDataFlow + int valueNum = data.entryValueNum + data.entryState.length; - // Add the values which are "consumed" by clearValues and mergeState in solveDataFlow - int valueNum = data.entryValueNum + data.entryState.length; - - int numInsts = instructions.size(); - for (int idx = 0; idx < numInsts; idx++) { - LIRInstruction op = instructions.get(idx); - if (isEligibleMove(op)) { - MoveOp moveOp = (MoveOp) op; - int sourceIdx = getStateIdx(moveOp.getInput()); - int destIdx = getStateIdx(moveOp.getResult()); - if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) { - assert iterState[sourceIdx] != INIT_VALUE; - indent2.log("delete move %s", op); - instructions.set(idx, null); - hasDead = true; + int numInsts = instructions.size(); + for (int idx = 0; idx < numInsts; idx++) { + LIRInstruction op = instructions.get(idx); + if (isEligibleMove(op)) { + MoveOp moveOp = (MoveOp) op; + int sourceIdx = getStateIdx(moveOp.getInput()); + int destIdx = getStateIdx(moveOp.getResult()); + if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) { + assert iterState[sourceIdx] != INIT_VALUE; + Debug.log("delete move %s", op); + instructions.set(idx, null); + hasDead = true; + } + } + // It doesn't harm if updateState is also called for a deleted move + valueNum = updateState(iterState, op, valueNum); + } + if (hasDead) { + instructions.removeAll(Collections.singleton(null)); } } - // It doesn't harm if updateState is also called for a deleted move - valueNum = updateState(iterState, op, valueNum); } - if (hasDead) { - instructions.removeAll(Collections.singleton(null)); - } - indent2.outdent(); } - indent.outdent(); } /** @@ -338,7 +340,7 @@ if (sourceIdx >= 0 && destIdx >= 0) { assert isObjectValue(state[sourceIdx]) || (moveOp.getInput().getKind() != Kind.Object) : "move op moves object but input is not defined as object"; state[destIdx] = state[sourceIdx]; - indent.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx); + Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx); return initValueNum; } } @@ -346,7 +348,7 @@ int valueNum = initValueNum; if (op.destroysCallerSavedRegisters()) { - indent.log("kill all caller save regs"); + Debug.log("kill all caller save regs"); for (Register reg : callerSaveRegs) { if (reg.number < numRegs) { @@ -375,7 +377,7 @@ * Assign a unique number to the output or temp location. */ state[stateIdx] = encodeValueNum(opValueNum++, operand.getKind() == Kind.Object); - indent.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]); + Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]); } return operand; } @@ -395,12 +397,11 @@ /* * All instructions with framestates (mostly method calls), may do garbage * collection. GC will rewrite all object references which are live at this point. - * So we can't rely on their values. - * - * It would be sufficient to just kill all values which are referenced in the state - * (or all values which are not), but for simplicity we kill all values. + * So we can't rely on their values. It would be sufficient to just kill all values + * which are referenced in the state (or all values which are not), but for + * simplicity we kill all values. */ - indent.log("kill all object values"); + Debug.log("kill all object values"); clearValuesOfKindObject(state, valueNum); valueNum += state.length; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Sun Mar 30 16:08:33 2014 +0200 @@ -182,20 +182,20 @@ /** * The block in which this instruction is located. */ - final Block block; + final AbstractBlock block; /** * The block index of this instruction. */ final int index; - public NoOp(Block block, int index) { + public NoOp(AbstractBlock block, int index) { this.block = block; this.index = index; } public void replace(LIR lir, LIRInstruction replacement) { - lir.lir(block).set(index, replacement); + lir.getLIRforBlock(block).set(index, replacement); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Sun Mar 30 16:08:33 2014 +0200 @@ -301,7 +301,7 @@ */ public boolean isSuccessorEdge(LabelRef edge) { assert lir != null; - List order = lir.codeEmittingOrder(); + List> order = lir.codeEmittingOrder(); assert order.get(currentBlockIndex) == edge.getSourceBlock(); return currentBlockIndex < order.size() - 1 && order.get(currentBlockIndex + 1) == edge.getTargetBlock(); } @@ -315,7 +315,7 @@ this.lir = lir; this.currentBlockIndex = 0; frameContext.enter(this); - for (Block b : lir.codeEmittingOrder()) { + for (AbstractBlock b : lir.codeEmittingOrder()) { emitBlock(b); currentBlockIndex++; } @@ -323,12 +323,12 @@ this.currentBlockIndex = 0; } - private void emitBlock(Block block) { + private void emitBlock(AbstractBlock block) { if (Debug.isDumpEnabled()) { blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); } - for (LIRInstruction op : lir.lir(block)) { + for (LIRInstruction op : lir.getLIRforBlock(block)) { if (Debug.isDumpEnabled()) { blockComment(String.format("%d %s", op.id(), op)); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java Sun Mar 30 16:08:33 2014 +0200 @@ -63,7 +63,7 @@ } private void findDerived(Collection bivs) { - Queue scanQueue = new LinkedList(bivs); + Queue scanQueue = new LinkedList<>(bivs); while (!scanQueue.isEmpty()) { InductionVariable baseIv = scanQueue.remove(); ValueNode baseIvNode = baseIv.valueNode(); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Sun Mar 30 16:08:33 2014 +0200 @@ -141,7 +141,7 @@ BinaryNode result = BinaryNode.reassociate(binary, invariant); if (result != binary) { if (Debug.isLogEnabled()) { - Debug.log(MetaUtil.format("%H::%n", Debug.contextLookup(ResolvedJavaMethod.class)) + " : Reassociated %s into %s", binary, result); + Debug.log("%s : Reassociated %s into %s", MetaUtil.format("%H::%n", graph.method()), binary, result); } graph.replaceFloating(binary, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -84,6 +84,6 @@ } } sb.append("]"); - Debug.log(sb.toString()); + Debug.log("%s", sb); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -128,7 +128,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { // nop } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,13 +30,11 @@ * This node represents an unconditional explicit request for immediate deoptimization. * * After this node, execution will continue using a fallback execution engine (such as an - * interpreter) at the position described by the {@link #getDeoptimizationState() deoptimization - * state}. - * + * interpreter) at the position described by the {@link #stateBefore() deoptimization state}. */ -public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode { +public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode.DeoptBefore { - @Input private FrameState deoptState; + @Input private FrameState stateBefore; public AbstractDeoptimizeNode() { super(StampFactory.forVoid()); @@ -48,18 +46,14 @@ } @Override - public FrameState getDeoptimizationState() { - return deoptState; + public FrameState stateBefore() { + return stateBefore; } @Override - public void setDeoptimizationState(FrameState f) { - updateUsages(deoptState, f); - deoptState = f; - } - - public FrameState getState() { - return deoptState; + public void setStateBefore(FrameState f) { + updateUsages(stateBefore, f); + stateBefore = f; } public abstract ValueNode getActionAndReason(MetaAccessProvider metaAccess); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -35,7 +35,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.visitEndNode(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -86,7 +86,7 @@ FixedNode next = next(); setNext(null); DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason)); - deopt.setDeoptimizationState(getDeoptimizationState()); + deopt.setStateBefore(stateBefore()); IfNode ifNode; AbstractBeginNode noDeoptSuccessor; if (negated) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java Sun Mar 30 16:08:33 2014 +0200 @@ -41,10 +41,6 @@ stateAfter = x; } - public FrameState getState() { - return stateAfter(); - } - public boolean hasSideEffect() { return true; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -54,7 +54,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.visitBreakpointNode(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -54,7 +54,7 @@ public abstract String targetName(); @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { // nop } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -120,12 +120,12 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { assert ConstantNodeRecordsUsages : "LIR generator should generate constants per-usage"; - if (gen.canInlineConstant(value) || onlyUsedInVirtualState()) { + if (gen.getLIRGeneratorTool().canInlineConstant(value) || onlyUsedInVirtualState()) { gen.setResult(this, value); } else { - gen.setResult(this, gen.emitMove(value)); + gen.setResult(this, gen.getLIRGeneratorTool().emitMove(value)); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -62,8 +62,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.emitDeoptimize(gen.getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, this); + public void generate(NodeLIRGeneratorTool gen) { + gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, this); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,26 +24,22 @@ import com.oracle.graal.nodes.type.*; -public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode { +public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode.DeoptBefore { - @Input(notDataflow = true) private FrameState deoptState; + @Input(notDataflow = true) private FrameState stateBefore; public DeoptimizingFixedWithNextNode(Stamp stamp) { super(stamp); } @Override - public FrameState getDeoptimizationState() { - return deoptState; + public FrameState stateBefore() { + return stateBefore; } @Override - public void setDeoptimizationState(FrameState f) { - updateUsages(deoptState, f); - deoptState = f; - } - - public FrameState getState() { - return deoptState; + public void setStateBefore(FrameState f) { + updateUsages(stateBefore, f); + stateBefore = f; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -35,14 +35,46 @@ boolean canDeoptimize(); /** - * Gets the deoptimization information associated with this node if any. + * Interface for nodes that need a {@link FrameState} for deoptimizing to a point before their + * execution. */ - FrameState getDeoptimizationState(); + public interface DeoptBefore extends DeoptimizingNode { + + /** + * Sets the {@link FrameState} describing the program state before the execution of this + * node. + */ + void setStateBefore(FrameState state); + + FrameState stateBefore(); + } + + /** + * Interface for nodes that need a {@link FrameState} for deoptimizing to a point after their + * execution. + */ + public interface DeoptAfter extends DeoptimizingNode, StateSplit { + } /** - * Sets the deoptimization information associated with this node. - * - * @param state the {@link FrameState} which represents the deoptimization information + * Interface for nodes that need a special {@link FrameState} for deoptimizing during their + * execution (e.g. {@link Invoke}). */ - void setDeoptimizationState(FrameState state); + public interface DeoptDuring extends DeoptimizingNode, StateSplit { + + FrameState stateDuring(); + + /** + * Sets the {@link FrameState} describing the program state during the execution of this + * node. + */ + void setStateDuring(FrameState state); + + /** + * Compute the {@link FrameState} describing the program state during the execution of this + * node from an input {@link FrameState} describing the program state after finishing the + * execution of this node. + */ + void computeStateDuring(FrameState stateAfter); + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -54,8 +54,8 @@ return getSpeculation(); } - public void generate(LIRGeneratorTool generator) { - generator.emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), this); + public void generate(NodeLIRGeneratorTool generator) { + generator.getLIRGeneratorTool().emitDeoptimize(generator.operand(actionAndReason), generator.operand(speculation), this); } @Override @@ -66,7 +66,7 @@ DeoptimizeNode newDeopt = graph().add( new DeoptimizeNode(tool.getMetaAccess().decodeDeoptAction(constant), tool.getMetaAccess().decodeDeoptReason(constant), tool.getMetaAccess().decodeDebugId(constant), speculationConstant)); - newDeopt.setDeoptimizationState(getDeoptimizationState()); + newDeopt.setStateBefore(stateBefore()); return newDeopt; } return this; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -38,7 +38,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { throw new GraalInternalError("OnStackReplacementNode should not survive"); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -52,7 +52,7 @@ } DeoptimizeNode deopt = graph().add(new DeoptimizeNode(getAction(), getReason())); - deopt.setDeoptimizationState(getDeoptimizationState()); + deopt.setStateBefore(stateBefore()); setNext(deopt); } this.replaceAtUsages(null); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Sun Mar 30 16:08:33 2014 +0200 @@ -254,12 +254,12 @@ copy.remove(copy.size() - 1); } ValueNode lastSlot = copy.get(copy.size() - 1); - assert lastSlot.kind().getStackKind() == popKind.getStackKind(); + assert lastSlot.getKind().getStackKind() == popKind.getStackKind(); copy.remove(copy.size() - 1); } for (ValueNode node : pushedValues) { copy.add(node); - if (node.kind() == Kind.Long || node.kind() == Kind.Double) { + if (node.getKind() == Kind.Long || node.getKind() == Kind.Double) { copy.add(null); } } @@ -404,7 +404,7 @@ assertTrue(values.size() - localsSize - stackSize == monitorIds.size(), "mismatch in number of locks"); for (ValueNode value : values) { assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes"); - assertTrue(value == null || value instanceof VirtualObjectNode || (value.kind() != Kind.Void), "unexpected value: %s", value); + assertTrue(value == null || value instanceof VirtualObjectNode || (value.getKind() != Kind.Void), "unexpected value: %s", value); } return super.verify(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -53,8 +53,8 @@ } @Override - public void generate(LIRGeneratorTool generator) { - if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) { + public void generate(NodeLIRGeneratorTool generator) { + if (object.getKind() != Kind.Void && object.getKind() != Kind.Illegal) { generator.setResult(this, generator.operand(object)); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -99,7 +99,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (stamp() == StampFactory.illegal(object.kind())) { + if (stamp() == StampFactory.illegal(object.getKind())) { // The guard always fails return graph().add(new DeoptimizeNode(action, reason)); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -42,7 +43,7 @@ * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome * of a comparison. */ -public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable { +public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable { @Successor private AbstractBeginNode trueSuccessor; @Successor private AbstractBeginNode falseSuccessor; @@ -126,11 +127,16 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.emitIf(this); } @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + return gen.emitIfMemory(this, access); + } + + @Override public boolean verify() { assertTrue(condition() != null, "missing condition"); assertTrue(trueSuccessor() != null, "missing trueSuccessor"); @@ -356,10 +362,10 @@ boolean inverted = trueEnd == merge.forwardEndAt(1); ValueNode trueValue = singlePhi.valueAt(inverted ? 1 : 0); ValueNode falseValue = singlePhi.valueAt(inverted ? 0 : 1); - if (trueValue.kind() != falseValue.kind()) { + if (trueValue.getKind() != falseValue.getKind()) { return false; } - if (trueValue.kind() != Kind.Int && trueValue.kind() != Kind.Long) { + if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) { return false; } ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue); @@ -379,10 +385,10 @@ ValueNode falseValue = falseEnd.result(); ConditionalNode conditional = null; if (trueValue != null) { - if (trueValue.kind() != falseValue.kind()) { + if (trueValue.getKind() != falseValue.getKind()) { return false; } - if (trueValue.kind() != Kind.Int && trueValue.kind() != Kind.Long) { + if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) { return false; } conditional = canonicalizeConditionalCascade(trueValue, falseValue); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -41,7 +41,7 @@ } @Override - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { generator.visitInfopointNode(this); } @@ -51,7 +51,7 @@ @Override public boolean verify() { - return getState() != null && super.verify(); + return state != null && super.verify(); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; -public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode, GuardedNode { +public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, GuardedNode { FixedNode next(); @@ -38,10 +38,6 @@ FixedNode asNode(); - FrameState stateDuring(); - - FrameState stateAfter(); - Node predecessor(); void intrinsify(Node node); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -38,7 +38,7 @@ public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single { @Input private CallTargetNode callTarget; - @Input private FrameState deoptState; + @Input private FrameState stateDuring; @Input private GuardingNode guard; private final int bci; private boolean polymorphic; @@ -113,7 +113,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.emitInvoke(this); } @@ -133,19 +133,8 @@ } @Override - public FrameState stateDuring() { - FrameState stateAfter = stateAfter(); - if (stateAfter == null) { - return null; - } - FrameState stateDuring = stateAfter.duplicateModified(bci(), stateAfter.rethrowException(), kind()); - stateDuring.setDuringCall(true); - return stateDuring; - } - - @Override public void intrinsify(Node node) { - assert !(node instanceof ValueNode) || (((ValueNode) node).kind() == Kind.Void) == (kind() == Kind.Void); + assert !(node instanceof ValueNode) || (((ValueNode) node).getKind() == Kind.Void) == (getKind() == Kind.Void); CallTargetNode call = callTarget; FrameState stateAfter = stateAfter(); if (node instanceof StateSplit) { @@ -174,18 +163,21 @@ } @Override - public FrameState getDeoptimizationState() { - if (deoptState == null) { - FrameState stateDuring = stateDuring(); - updateUsages(deoptState, stateDuring); - deoptState = stateDuring; - } - return deoptState; + public FrameState stateDuring() { + return stateDuring; } @Override - public void setDeoptimizationState(FrameState f) { - throw new IllegalStateException("Cannot set deoptimization state " + f + " for invoke " + this); + public void setStateDuring(FrameState stateDuring) { + updateUsages(this.stateDuring, stateDuring); + this.stateDuring = stateDuring; + } + + @Override + public void computeStateDuring(FrameState stateAfter) { + FrameState newStateDuring = stateAfter.duplicateModified(bci(), stateAfter.rethrowException(), getKind()); + newStateDuring.setDuringCall(true); + setStateDuring(newStateDuring); } @Override @@ -198,14 +190,4 @@ updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); this.guard = guard; } - - @Override - public FrameState getState() { - if (deoptState != null) { - assert stateAfter() == null; - return deoptState; - } else { - return super.getState(); - } - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,7 +39,7 @@ @Successor private AbstractBeginNode next; @Successor private DispatchBeginNode exceptionEdge; @Input private CallTargetNode callTarget; - @Input private FrameState deoptState; + @Input private FrameState stateDuring; @Input private FrameState stateAfter; @Input private GuardingNode guard; private final int bci; @@ -133,7 +133,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.emitInvoke(this); } @@ -155,13 +155,6 @@ return LocationIdentity.ANY_LOCATION; } - public FrameState stateDuring() { - FrameState tempStateAfter = stateAfter(); - FrameState stateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), kind()); - stateDuring.setDuringCall(true); - return stateDuring; - } - @Override public Map getDebugProperties(Map map) { Map debugProperties = super.getDebugProperties(map); @@ -177,7 +170,7 @@ @Override public void intrinsify(Node node) { - assert !(node instanceof ValueNode) || (((ValueNode) node).kind() == Kind.Void) == (kind() == Kind.Void); + assert !(node instanceof ValueNode) || (((ValueNode) node).getKind() == Kind.Void) == (getKind() == Kind.Void); CallTargetNode call = callTarget; FrameState state = stateAfter(); killExceptionEdge(); @@ -186,7 +179,7 @@ stateSplit.setStateAfter(state); } if (node == null) { - assert kind() == Kind.Void && usages().isEmpty(); + assert getKind() == Kind.Void && usages().isEmpty(); graph().removeSplit(this, next()); } else if (node instanceof ControlSinkNode) { this.replaceAtPredecessor(node); @@ -219,18 +212,21 @@ } @Override - public FrameState getDeoptimizationState() { - if (deoptState == null) { - FrameState stateDuring = stateDuring(); - updateUsages(deoptState, stateDuring); - deoptState = stateDuring; - } - return deoptState; + public FrameState stateDuring() { + return stateDuring; } @Override - public void setDeoptimizationState(FrameState f) { - throw new IllegalStateException(); + public void setStateDuring(FrameState stateDuring) { + updateUsages(this.stateDuring, stateDuring); + this.stateDuring = stateDuring; + } + + @Override + public void computeStateDuring(FrameState tempStateAfter) { + FrameState newStateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), getKind()); + newStateDuring.setDuringCall(true); + setStateDuring(newStateDuring); } @Override @@ -244,16 +240,6 @@ this.guard = guard; } - @Override - public FrameState getState() { - if (deoptState != null) { - assert stateAfter() == null; - return deoptState; - } else { - return stateAfter(); - } - } - public MemoryCheckpoint asMemoryCheckpoint() { return this; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -68,7 +68,7 @@ } @Override - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { // nothing to do } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -98,7 +98,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { // Nothing to emit, since this is node is used for structural purposes only. } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -64,7 +64,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.visitLoopEnd(this); super.generate(gen); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -42,7 +42,7 @@ } @Override - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -41,7 +41,7 @@ @Input(notDataflow = true) private final NodeInputList ends = new NodeInputList<>(this); @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.visitMerge(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -62,8 +62,8 @@ } @Override - public void generate(LIRGeneratorTool generator) { - if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) { + public void generate(NodeLIRGeneratorTool generator) { + if (object.getKind() != Kind.Void && object.getKind() != Kind.Illegal) { generator.setResult(this, generator.operand(object)); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -57,7 +57,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.visitReturn(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -35,7 +35,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.visitSafepointNode(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,7 +39,7 @@ public UnwindNode(ValueNode exception) { super(StampFactory.forVoid()); - assert exception == null || exception.kind() == Kind.Object; + assert exception == null || exception.getKind() == Kind.Object; this.exception = exception; } @@ -49,7 +49,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.emitUnwind(gen.operand(exception())); + public void generate(NodeLIRGeneratorTool gen) { + gen.getLIRGeneratorTool().emitUnwind(gen.operand(exception())); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -31,7 +31,7 @@ * This class represents a value within the graph, including local variables, phis, and all other * instructions. */ -public abstract class ValueNode extends ScheduledNode implements StampProvider { +public abstract class ValueNode extends ScheduledNode implements StampProvider, KindInterface { /** * The kind of this value. This is {@link Kind#Void} for instructions that produce no value. @@ -79,7 +79,7 @@ return false; } - public final Kind kind() { + public final Kind getKind() { return stamp().getStackKind(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java Sun Mar 30 16:08:33 2014 +0200 @@ -32,7 +32,7 @@ public class ValueNodeUtil { public static ValueNode assertKind(Kind kind, ValueNode x) { - assert x != null && x.kind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind()); + assert x != null && x.getKind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind()); return x; } @@ -45,27 +45,27 @@ } public static ValueNode assertLong(ValueNode x) { - assert x != null && (x.kind() == Kind.Long); + assert x != null && (x.getKind() == Kind.Long); return x; } public static ValueNode assertInt(ValueNode x) { - assert x != null && (x.kind() == Kind.Int); + assert x != null && (x.getKind() == Kind.Int); return x; } public static ValueNode assertFloat(ValueNode x) { - assert x != null && (x.kind() == Kind.Float); + assert x != null && (x.getKind() == Kind.Float); return x; } public static ValueNode assertObject(ValueNode x) { - assert x != null && (x.kind() == Kind.Object); + assert x != null && (x.getKind() == Kind.Object); return x; } public static ValueNode assertDouble(ValueNode x) { - assert x != null && (x.kind() == Kind.Double); + assert x != null && (x.getKind() == Kind.Double); return x; } @@ -87,14 +87,14 @@ /** * Converts a given instruction to a value string. The representation of an node as a value is * formed by concatenating the {@linkplain com.oracle.graal.api.meta.Kind#getTypeChar character} - * denoting its {@linkplain ValueNode#kind kind} and its id. For example, {@code "i13"}. + * denoting its {@linkplain ValueNode#getKind kind} and its id. For example, {@code "i13"}. * * @param value the instruction to convert to a value string. If {@code value == null}, then "-" * is returned. * @return the instruction representation as a string */ public static String valueString(ValueNode value) { - return (value == null) ? "-" : ("" + value.kind().getTypeChar() + value.toString(Verbosity.Id)); + return (value == null) ? "-" : ("" + value.getKind().getTypeChar() + value.toString(Verbosity.Id)); } public static ValueNode asNode(MemoryNode node) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -80,7 +81,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitAnd(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitAnd(gen.operand(x()), gen.operand(y()))); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitAndMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,7 +29,7 @@ /** * The {@code LogicNode} class definition. */ -public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode { +public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode { /** * Constructs a new logic operation node. diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; /* TODO (thomaswue/gdub) For high-level optimization purpose the compare node should be a boolean *value* (it is currently only a helper node) @@ -34,7 +35,7 @@ * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed * into variants that do not materialize the value (CompareIf, CompareGuard...) */ -public abstract class CompareNode extends LogicNode implements Canonicalizable, LIRLowerable { +public abstract class CompareNode extends LogicNode implements Canonicalizable, LIRLowerable, MemoryArithmeticLIRLowerable { @Input private ValueNode x; @Input private ValueNode y; @@ -54,7 +55,7 @@ * @param y the instruction that produces the second input to this instruction */ public CompareNode(ValueNode x, ValueNode y) { - assert x != null && y != null && x.kind() == y.kind(); + assert x != null && y != null && x.getKind() == y.getKind(); this.x = x; this.y = y; } @@ -74,7 +75,7 @@ public abstract boolean unorderedIsTrue(); @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { } private LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) { @@ -169,27 +170,37 @@ } public static CompareNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) { - assert x.kind() == y.kind(); + assert x.getKind() == y.getKind(); assert condition.isCanonical() : "condition is not canonical: " + condition; - assert !x.kind().isNumericFloat(); + assert !x.getKind().isNumericFloat(); CompareNode comparison; if (condition == Condition.EQ) { - if (x.kind() == Kind.Object) { + if (x.getKind() == Kind.Object) { comparison = new ObjectEqualsNode(x, y); } else { - assert x.kind().isNumericInteger(); + assert x.getKind().isNumericInteger(); comparison = new IntegerEqualsNode(x, y); } } else if (condition == Condition.LT) { - assert x.kind().isNumericInteger(); + assert x.getKind().isNumericInteger(); comparison = new IntegerLessThanNode(x, y); } else { assert condition == Condition.BT; - assert x.kind().isNumericInteger(); + assert x.getKind().isNumericInteger(); comparison = new IntegerBelowThanNode(x, y); } return graph.unique(comparison); } + + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + return false; + } + + @Override + public boolean verify() { + assertTrue(x.stamp().isCompatible(y.stamp()), "stamps not compatible: %s, %s", x.stamp(), y.stamp()); + return super.verify(); + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -109,7 +109,7 @@ } @Override - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { generator.emitConditional(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -64,7 +65,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { Value op1 = gen.operand(x()); Value op2 = gen.operand(y()); if (!y().isConstant() && !livesLonger(this, y(), gen)) { @@ -72,15 +73,24 @@ op1 = op2; op2 = op; } - gen.setResult(this, gen.emitAdd(op1, op2)); + gen.setResult(this, gen.getLIRGeneratorTool().emitAdd(op1, op2)); } - public static boolean livesLonger(ValueNode after, ValueNode value, ArithmeticLIRGenerator gen) { + public static boolean livesLonger(ValueNode after, ValueNode value, NodeLIRGeneratorTool gen) { for (Node usage : value.usages()) { - if (usage != after && usage instanceof ValueNode && gen.operand(((ValueNode) usage)) != null) { + if (usage != after && usage instanceof ValueNode && gen.hasOperand(((ValueNode) usage))) { return true; } } return false; } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitAddMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable { +public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { private final boolean isStrictFP; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -33,7 +34,7 @@ * A {@code FloatConvert} converts between integers and floating point numbers according to Java * semantics. */ -public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable { +public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { public enum FloatConvert { F2I, D2I, F2L, D2L, I2F, L2F, D2F, I2D, L2D, F2D; @@ -191,7 +192,21 @@ tool.getLowerer().lower(this, tool); } - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitFloatConvert(op, gen.operand(getInput()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitFloatConvert(op, gen.operand(getInput()))); + } + + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Kind kind = access.nullCheckLocation().getValueKind(); + if (kind != kind.getStackKind()) { + // Doesn't work for subword operations + return false; + } + + Value result = gen.emitFloatConvertMemory(getOp(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -56,7 +57,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()), null)); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), null)); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitDivMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -59,7 +60,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { Value op1 = gen.operand(x()); Value op2 = gen.operand(y()); if (!y().isConstant() && !FloatAddNode.livesLonger(this, y(), gen)) { @@ -67,6 +68,15 @@ op1 = op2; op2 = op; } - gen.setResult(this, gen.emitMul(op1, op2)); + gen.setResult(this, gen.getLIRGeneratorTool().emitMul(op1, op2)); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitMulMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -56,7 +57,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()), null)); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), null)); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitRemMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -75,7 +76,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitSub(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitSub(gen.operand(x()), gen.operand(y()))); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitSubMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -78,9 +79,6 @@ if (reassociated != this) { return reassociated; } - if (c < 0) { - return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph())); - } } if (x() instanceof NegateNode) { return IntegerArithmeticNode.sub(graph(), y(), ((NegateNode) x()).x()); @@ -91,7 +89,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { Value op1 = gen.operand(x()); assert op1 != null : x() + ", this=" + this; Value op2 = gen.operand(y()); @@ -100,6 +98,15 @@ op1 = op2; op2 = op; } - gen.setResult(this, gen.emitAdd(op1, op2)); + gen.setResult(this, gen.getLIRGeneratorTool().emitAdd(op1, op2)); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitAddMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable { +public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) { super(stamp, x, y); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,8 +39,8 @@ */ public IntegerBelowThanNode(ValueNode x, ValueNode y) { super(x, y); - assert !x.kind().isNumericFloat() && x.kind() != Kind.Object; - assert !y.kind().isNumericFloat() && y.kind() != Kind.Object; + assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object; + assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -31,7 +31,7 @@ /** * An {@code IntegerConvert} converts an integer to an integer of different width. */ -public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable { +public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable { private final int resultBits; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -106,8 +106,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()), this)); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitDiv(gen.operand(x()), gen.operand(y()), this)); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,8 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "==") public final class IntegerEqualsNode extends CompareNode { @@ -38,8 +40,8 @@ */ public IntegerEqualsNode(ValueNode x, ValueNode y) { super(x, y); - assert !x.kind().isNumericFloat() && x.kind() != Kind.Object; - assert !y.kind().isNumericFloat() && y.kind() != Kind.Object; + assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object; + assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object; } @Override @@ -58,7 +60,7 @@ ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x(); ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y(); - if (normalizeNode.x().kind() == Kind.Double || normalizeNode.x().kind() == Kind.Float) { + if (normalizeNode.x().getKind() == Kind.Double || normalizeNode.x().getKind() == Kind.Float) { return graph().unique(new FloatEqualsNode(a, b)); } else { return graph().unique(new IntegerEqualsNode(a, b)); @@ -69,17 +71,67 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (x() == y()) { + if (GraphUtil.unproxify(x()) == GraphUtil.unproxify(y())) { return LogicConstantNode.tautology(graph()); } else if (x().stamp().alwaysDistinct(y().stamp())) { return LogicConstantNode.contradiction(graph()); } - if (x() instanceof AndNode && y().isConstant() && y().asConstant().asLong() == 0) { - return graph().unique(new IntegerTestNode(((AndNode) x()).x(), ((AndNode) x()).y())); - } else if (y() instanceof AndNode && x().isConstant() && x().asConstant().asLong() == 0) { - return graph().unique(new IntegerTestNode(((AndNode) y()).x(), ((AndNode) y()).y())); + ValueNode result = canonicalizeSymmetric(x(), y()); + if (result != null) { + return result; } + + result = canonicalizeSymmetric(y(), x()); + if (result != null) { + return result; + } + return super.canonical(tool); } + + private ValueNode canonicalizeSymmetric(ValueNode x, ValueNode y) { + if (y.isConstant() && y.asConstant().asLong() == 0) { + if (x instanceof AndNode) { + return graph().unique(new IntegerTestNode(((AndNode) x).x(), ((AndNode) x).y())); + } else if (x instanceof LeftShiftNode) { + LeftShiftNode shift = (LeftShiftNode) x; + if (shift.y().isConstant()) { + int mask = shift.getShiftAmountMask(); + int amount = shift.y().asConstant().asInt() & mask; + if (shift.x().getKind() == Kind.Int) { + return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 >>> amount, graph()))); + } else { + assert shift.x().getKind() == Kind.Long; + return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L >>> amount, graph()))); + } + } + } else if (x instanceof RightShiftNode) { + RightShiftNode shift = (RightShiftNode) x; + if (shift.y().isConstant() && ((IntegerStamp) shift.x().stamp()).isPositive()) { + int mask = shift.getShiftAmountMask(); + int amount = shift.y().asConstant().asInt() & mask; + if (shift.x().getKind() == Kind.Int) { + return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph()))); + } else { + assert shift.x().getKind() == Kind.Long; + return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph()))); + } + } + } else if (x instanceof UnsignedRightShiftNode) { + UnsignedRightShiftNode shift = (UnsignedRightShiftNode) x; + if (shift.y().isConstant()) { + int mask = shift.getShiftAmountMask(); + int amount = shift.y().asConstant().asInt() & mask; + if (shift.x().getKind() == Kind.Int) { + return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph()))); + } else { + assert shift.x().getKind() == Kind.Long; + return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph()))); + } + } + } + } + return null; + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,8 +39,8 @@ */ public IntegerLessThanNode(ValueNode x, ValueNode y) { super(x, y); - assert !x.kind().isNumericFloat() && x.kind() != Kind.Object; - assert !y.kind().isNumericFloat() && y.kind() != Kind.Object; + assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object; + assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object; } @Override @@ -60,7 +60,7 @@ ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x(); ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y(); - if (normalizeNode.x().kind() == Kind.Double || normalizeNode.x().kind() == Kind.Float) { + if (normalizeNode.x().getKind() == Kind.Double || normalizeNode.x().getKind() == Kind.Float) { return graph().unique(new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess)); } else { return graph().unique(new IntegerLessThanNode(a, b)); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -74,7 +75,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { Value op1 = gen.operand(x()); Value op2 = gen.operand(y()); if (!y().isConstant() && !FloatAddNode.livesLonger(this, y(), gen)) { @@ -82,6 +83,15 @@ op1 = op2; op2 = op; } - gen.setResult(this, gen.emitMul(op1, op2)); + gen.setResult(this, gen.getLIRGeneratorTool().emitMul(op1, op2)); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitMulMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -61,8 +61,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()), this)); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitRem(gen.operand(x()), gen.operand(y()), this)); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -97,7 +98,9 @@ if (reassociated != this) { return reassociated; } - if (c < 0) { + if (c < 0 || ((IntegerStamp) StampFactory.forKind(y().getKind())).contains(-c)) { + // Adding a negative is more friendly to the backend since adds are + // commutative, so prefer add when it fits. return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph())); } } else if (x().isConstant()) { @@ -114,7 +117,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitSub(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitSub(gen.operand(x()), gen.operand(y()))); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitSubMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -25,6 +25,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -33,7 +34,7 @@ * expression "(x & y) == 0", meaning that it will return true if (and only if) no bit is set in * both x and y. */ -public class IntegerTestNode extends LogicNode implements Canonicalizable, LIRLowerable { +public class IntegerTestNode extends LogicNode implements Canonicalizable, LIRLowerable, MemoryArithmeticLIRLowerable { @Input private ValueNode x; @Input private ValueNode y; @@ -59,7 +60,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { } @Override @@ -76,4 +77,9 @@ } return this; } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + return false; + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -50,7 +50,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { // Nothing to do. } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -44,10 +44,10 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Int) { + if (getKind() == Kind.Int) { return Constant.forInt(inputs[0].asInt() << inputs[1].asInt()); } else { - assert kind() == Kind.Long; + assert getKind() == Kind.Long; return Constant.forLong(inputs[0].asLong() << inputs[1].asLong()); } } @@ -59,13 +59,7 @@ } else if (y().isConstant()) { int amount = y().asConstant().asInt(); int originalAmout = amount; - int mask; - if (kind() == Kind.Int) { - mask = 0x1f; - } else { - assert kind() == Kind.Long; - mask = 0x3f; - } + int mask = getShiftAmountMask(); amount &= mask; if (amount == 0) { return x(); @@ -77,14 +71,14 @@ if (other instanceof LeftShiftNode) { int total = amount + otherAmount; if (total != (total & mask)) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerKind(getKind(), 0, graph()); } return graph().unique(new LeftShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph()))); } else if ((other instanceof RightShiftNode || other instanceof UnsignedRightShiftNode) && otherAmount == amount) { - if (kind() == Kind.Long) { + if (getKind() == Kind.Long) { return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L << amount, graph()))); } else { - assert kind() == Kind.Int; + assert getKind() == Kind.Int; return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 << amount, graph()))); } } @@ -98,7 +92,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitShl(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitShl(gen.operand(x()), gen.operand(y()))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -109,7 +110,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitNarrow(gen.operand(getInput()), getResultBits())); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitNarrow(gen.operand(getInput()), getResultBits())); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitNarrowMemory(getResultBits(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -88,7 +88,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitNegate(gen.operand(x()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitNegate(gen.operand(x()))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -73,7 +73,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitNot(gen.operand(x()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitNot(gen.operand(x()))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -40,8 +40,8 @@ */ public ObjectEqualsNode(ValueNode x, ValueNode y) { super(x, y); - assert x.kind() == Kind.Object; - assert y.kind() == Kind.Object; + assert x.getKind() == Kind.Object; + assert y.getKind() == Kind.Object; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -72,7 +73,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitOr(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitOr(gen.operand(x()), gen.operand(y()))); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitOrMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -34,7 +35,7 @@ * of a primitive value to some other incompatible stamp. The new stamp must have the same width as * the old stamp. */ -public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable { +public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable { @Input private ValueNode value; @@ -101,9 +102,18 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - PlatformKind kind = gen.getPlatformKind(stamp()); - gen.setResult(this, gen.emitReinterpret(kind, gen.operand(value()))); + public void generate(NodeLIRGeneratorTool gen) { + PlatformKind kind = gen.getLIRGeneratorTool().getPlatformKind(stamp()); + gen.setResult(this, gen.getLIRGeneratorTool().emitReinterpret(kind, gen.operand(value()))); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitReinterpretMemory(stamp(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } public static ValueNode reinterpret(Kind toKind, ValueNode value) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,10 +39,10 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Int) { + if (getKind() == Kind.Int) { return Constant.forInt(inputs[0].asInt() >> inputs[1].asInt()); } else { - assert kind() == Kind.Long; + assert getKind() == Kind.Long; return Constant.forLong(inputs[0].asLong() >> inputs[1].asLong()); } } @@ -57,13 +57,7 @@ } else if (y().isConstant()) { int amount = y().asConstant().asInt(); int originalAmout = amount; - int mask; - if (kind() == Kind.Int) { - mask = 0x1f; - } else { - assert kind() == Kind.Long; - mask = 0x3f; - } + int mask = getShiftAmountMask(); amount &= mask; if (amount == 0) { return x(); @@ -79,10 +73,10 @@ IntegerStamp istamp = (IntegerStamp) other.x().stamp(); if (istamp.isPositive()) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerKind(getKind(), 0, graph()); } if (istamp.isStrictlyNegative()) { - return ConstantNode.forIntegerKind(kind(), -1L, graph()); + return ConstantNode.forIntegerKind(getKind(), -1L, graph()); } /* @@ -104,7 +98,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitShr(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitShr(gen.operand(x()), gen.operand(y()))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -40,4 +41,15 @@ public ShiftNode(Stamp stamp, ValueNode x, ValueNode s) { super(stamp, x, s); } + + public int getShiftAmountMask() { + int mask; + if (getKind() == Kind.Int) { + mask = 0x1f; + } else { + assert getKind() == Kind.Long; + mask = 0x3f; + } + return mask; + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -104,7 +105,17 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitSignExtend(gen.operand(getInput()), getInputBits(), getResultBits())); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitSignExtend(gen.operand(getInput()), getInputBits(), getResultBits())); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + assert !access.nullCheckLocation().getValueKind().isUnsigned() : "can't sign extend unsigned value"; + Value result = gen.emitSignExtendMemory(access, access.nullCheckLocation().getValueKind().getBitCount(), getResultBits()); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -71,8 +71,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitUDiv(gen.operand(x()), gen.operand(y()), this)); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitUDiv(gen.operand(x()), gen.operand(y()), this)); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -70,8 +70,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitURem(gen.operand(x()), gen.operand(y()), this)); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitURem(gen.operand(x()), gen.operand(y()), this)); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -44,10 +44,10 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Int) { + if (getKind() == Kind.Int) { return Constant.forInt(inputs[0].asInt() >>> inputs[1].asInt()); } else { - assert kind() == Kind.Long; + assert getKind() == Kind.Long; return Constant.forLong(inputs[0].asLong() >>> inputs[1].asLong()); } } @@ -59,13 +59,7 @@ } else if (y().isConstant()) { int amount = y().asConstant().asInt(); int originalAmout = amount; - int mask; - if (kind() == Kind.Int) { - mask = 0x1f; - } else { - assert kind() == Kind.Long; - mask = 0x3f; - } + int mask = getShiftAmountMask(); amount &= mask; if (amount == 0) { return x(); @@ -77,14 +71,14 @@ if (other instanceof UnsignedRightShiftNode) { int total = amount + otherAmount; if (total != (total & mask)) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerKind(getKind(), 0, graph()); } return graph().unique(new UnsignedRightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph()))); } else if (other instanceof LeftShiftNode && otherAmount == amount) { - if (kind() == Kind.Long) { + if (getKind() == Kind.Long) { return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L >>> amount, graph()))); } else { - assert kind() == Kind.Int; + assert getKind() == Kind.Int; return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 >>> amount, graph()))); } } @@ -98,7 +92,7 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitUShr(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitUShr(gen.operand(x()), gen.operand(y()))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -71,7 +72,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitXor(gen.operand(x()), gen.operand(y()))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitXor(gen.operand(x()), gen.operand(y()))); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitXorMemory(x(), y(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -84,7 +85,16 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitZeroExtend(gen.operand(getInput()), getInputBits(), getResultBits())); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitZeroExtend(gen.operand(getInput()), getInputBits(), getResultBits())); + } + + @Override + public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) { + Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access); + if (result != null) { + gen.setResult(this, result); + } + return result != null; } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,14 +22,12 @@ */ package com.oracle.graal.nodes.cfg; -import com.oracle.graal.nodes.*; +import java.util.*; public interface AbstractBlock> { int getId(); - AbstractBeginNode getBeginNode(); - Loop getLoop(); int getLoopDepth(); @@ -40,11 +38,11 @@ boolean isExceptionEntry(); - Iterable getPredecessors(); + List getPredecessors(); int getPredecessorCount(); - Iterable getSuccessors(); + List getSuccessors(); int getSuccessorCount(); @@ -55,4 +53,6 @@ boolean isAligned(); void setAlign(boolean align); + + T getDominator(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlockBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlockBase.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.cfg; + +import java.util.*; + +public abstract class AbstractBlockBase> implements AbstractBlock { + + protected int id; + + protected List predecessors; + protected List successors; + + protected T dominator; + + private boolean align; + private int linearScanNumber; + + protected AbstractBlockBase() { + this.id = ControlFlowGraph.BLOCK_ID_INITIAL; + this.linearScanNumber = -1; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public List getPredecessors() { + return predecessors; + } + + public List getSuccessors() { + return successors; + } + + public T getDominator() { + return dominator; + } + + @Override + public String toString() { + return "B" + id; + } + + public int getPredecessorCount() { + return getPredecessors().size(); + } + + public int getSuccessorCount() { + return getSuccessors().size(); + } + + public int getLinearScanNumber() { + return linearScanNumber; + } + + public void setLinearScanNumber(int linearScanNumber) { + this.linearScanNumber = linearScanNumber; + } + + public boolean isAligned() { + return align; + } + + public void setAlign(boolean align) { + this.align = align; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractControlFlowGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractControlFlowGraph.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, 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.nodes.cfg; + +public interface AbstractControlFlowGraph> { + + T[] getBlocks(); + + Loop[] getLoops(); + + T getStartBlock(); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,34 +27,18 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; -public final class Block implements AbstractBlock { +public final class Block extends AbstractBlockBase { protected final AbstractBeginNode beginNode; - protected int id; - protected FixedNode endNode; protected Loop loop; - protected List predecessors; - protected List successors; - - protected Block dominator; protected List dominated; protected Block postdominator; - private boolean align; - private int linearScanNumber; - protected Block(AbstractBeginNode node) { this.beginNode = node; - - this.id = ControlFlowGraph.BLOCK_ID_INITIAL; - this.linearScanNumber = -1; - } - - public int getId() { - return id; } public AbstractBeginNode getBeginNode() { @@ -89,22 +73,10 @@ return predecessors.get(0); } - public List getPredecessors() { - return predecessors; - } - public Block getFirstSuccessor() { return successors.get(0); } - public List getSuccessors() { - return successors; - } - - public Block getDominator() { - return dominator; - } - public Block getEarliestPostDominated() { Block b = this; while (true) { @@ -187,14 +159,6 @@ return "B" + id; } - public int getPredecessorCount() { - return getPredecessors().size(); - } - - public int getSuccessorCount() { - return getSuccessors().size(); - } - public boolean dominates(Block block) { return block.isDominatedBy(this); } @@ -209,19 +173,4 @@ return dominator.isDominatedBy(block); } - public int getLinearScanNumber() { - return linearScanNumber; - } - - public void setLinearScanNumber(int linearScanNumber) { - this.linearScanNumber = linearScanNumber; - } - - public boolean isAligned() { - return align; - } - - public void setAlign(boolean align) { - this.align = align; - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlockMap.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlockMap.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlockMap.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,7 +27,7 @@ private final T[] data; @SuppressWarnings("unchecked") - public BlockMap(ControlFlowGraph cfg) { + public BlockMap(AbstractControlFlowGraph cfg) { data = (T[]) new Object[cfg.getBlocks().length]; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlocksToDoubles.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlocksToDoubles.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.cfg; + +import java.util.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; + +public class BlocksToDoubles { + + private final IdentityHashMap, Double> nodeProbabilities; + + public BlocksToDoubles(int numberOfNodes) { + this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes); + } + + public void put(AbstractBlock n, double value) { + assert value >= 0.0 : value; + nodeProbabilities.put(n, value); + } + + public boolean contains(AbstractBlock n) { + return nodeProbabilities.containsKey(n); + } + + public double get(AbstractBlock n) { + Double value = nodeProbabilities.get(n); + assert value != null; + return value; + } + + public static BlocksToDoubles createFromNodeProbability(NodesToDoubles nodeProbabilities, ControlFlowGraph cfg) { + BlocksToDoubles blockProbabilities = new BlocksToDoubles(cfg.getBlocks().length); + for (Block block : cfg.getBlocks()) { + blockProbabilities.put(block, nodeProbabilities.get(block.getBeginNode())); + } + assert verify(nodeProbabilities, cfg, blockProbabilities) : "Probabilities differ for nodes in the same block."; + return blockProbabilities; + } + + private static boolean verify(NodesToDoubles nodeProbabilities, ControlFlowGraph cfg, BlocksToDoubles blockProbabilities) { + for (Block b : cfg.getBlocks()) { + double p = blockProbabilities.get(b); + for (FixedNode n : b.getNodes()) { + if (nodeProbabilities.get(n) != p) { + return false; + } + } + } + return true; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Sun Mar 30 16:08:33 2014 +0200 @@ -28,7 +28,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -public class ControlFlowGraph { +public class ControlFlowGraph implements AbstractControlFlowGraph { public final StructuredGraph graph; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -107,7 +107,7 @@ } @Override - public Value generateAddress(LIRGeneratorTool gen, Value base) { + public Value generateAddress(NodeLIRGeneratorTool gen, Value base) { Value xAddr = getX().generateAddress(gen, base); return getY().generateAddress(gen, xAddr); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -48,7 +48,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { Value addr = getLocation().generateAddress(gen, gen.operand(getObject())); gen.setResult(this, addr); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -65,7 +65,7 @@ } @Override - public Value generateAddress(LIRGeneratorTool gen, Value base) { - return gen.emitAddress(base, getDisplacement(), Value.ILLEGAL, 0); + public Value generateAddress(NodeLIRGeneratorTool gen, Value base) { + return gen.getLIRGeneratorTool().emitAddress(base, getDisplacement(), Value.ILLEGAL, 0); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -43,6 +43,11 @@ return object; } + protected void setObject(ValueNode x) { + updateUsages(object, x); + object = x; + } + public LocationNode location() { return (LocationNode) location; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -49,7 +49,7 @@ public static native T getObject(Object object); @Override - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { generator.setResult(this, generator.operand(object)); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -60,13 +60,16 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { Value address = location().generateAddress(gen, gen.operand(object())); - gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this)); + gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(location().getValueKind(), address, this)); } @Override public Node canonical(CanonicalizerTool tool) { + if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { + return graph().unique(new FloatingReadNode(((PiNode) object()).getOriginalValue(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType(), isCompressible())); + } return ReadNode.canonicalizeRead(this, location(), object(), tool, isCompressible()); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -35,11 +35,11 @@ * Node for a {@linkplain ForeignCallDescriptor foreign} call. */ @NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}") -public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode, MemoryCheckpoint.Multi { +public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode.DeoptDuring, MemoryCheckpoint.Multi { @Input private final NodeInputList arguments; private final ForeignCallsProvider foreignCalls; - @Input private FrameState deoptState; + @Input private FrameState stateDuring; private final ForeignCallDescriptor descriptor; @@ -82,7 +82,7 @@ return foreignCalls.getKilledLocations(descriptor); } - protected Value[] operands(LIRGeneratorTool gen) { + protected Value[] operands(NodeLIRGeneratorTool gen) { Value[] operands = new Value[arguments.size()]; for (int i = 0; i < operands.length; i++) { operands[i] = gen.operand(arguments.get(i)); @@ -91,42 +91,35 @@ } @Override - public void generate(LIRGeneratorTool gen) { - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(descriptor); + public void generate(NodeLIRGeneratorTool gen) { + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor); Value[] operands = operands(gen); - Value result = gen.emitForeignCall(linkage, this, operands); + Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, this, operands); if (result != null) { gen.setResult(this, result); } } @Override - public FrameState getDeoptimizationState() { - if (deoptState != null) { - return deoptState; - } else if (stateAfter() != null && canDeoptimize()) { - FrameState stateDuring = stateAfter(); - if ((stateDuring.stackSize() > 0 && stateDuring.stackAt(stateDuring.stackSize() - 1) == this) || (stateDuring.stackSize() > 1 && stateDuring.stackAt(stateDuring.stackSize() - 2) == this)) { - stateDuring = stateDuring.duplicateModified(stateDuring.bci, stateDuring.rethrowException(), this.kind()); - } - setDeoptimizationState(stateDuring); - return stateDuring; - } - return null; + public FrameState stateDuring() { + return stateDuring; } @Override - public void setDeoptimizationState(FrameState f) { - updateUsages(deoptState, f); - assert deoptState == null && canDeoptimize() : "shouldn't assign deoptState to " + this; - deoptState = f; + public void setStateDuring(FrameState stateDuring) { + updateUsages(this.stateDuring, stateDuring); + this.stateDuring = stateDuring; } @Override - public void setStateAfter(FrameState x) { - if (hasSideEffect()) { - super.setStateAfter(x); + public void computeStateDuring(FrameState stateAfter) { + FrameState newStateDuring; + if ((stateAfter.stackSize() > 0 && stateAfter.stackAt(stateAfter.stackSize() - 1) == this) || (stateAfter.stackSize() > 1 && stateAfter.stackAt(stateAfter.stackSize() - 2) == this)) { + newStateDuring = stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), this.getKind()); + } else { + newStateDuring = stateAfter; } + setStateDuring(newStateDuring); } @Override @@ -141,14 +134,4 @@ public boolean canDeoptimize() { return foreignCalls.canDeoptimize(descriptor); } - - @Override - public FrameState getState() { - if (deoptState != null) { - assert stateAfter() == null; - return deoptState; - } else { - return super.getState(); - } - } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -96,7 +96,7 @@ } @Override - public Value generateAddress(LIRGeneratorTool gen, Value base) { - return gen.emitAddress(base, displacement, gen.operand(getIndex()), getIndexScaling()); + public Value generateAddress(NodeLIRGeneratorTool gen, Value base) { + return gen.getLIRGeneratorTool().emitAddress(base, displacement, gen.operand(getIndex()), getIndexScaling()); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -101,7 +101,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.emitSwitch(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -56,9 +56,9 @@ public abstract LocationIdentity getLocationIdentity(); @Override - public final void generate(LIRGeneratorTool generator) { + public final void generate(NodeLIRGeneratorTool generator) { // nothing to do... } - public abstract Value generateAddress(LIRGeneratorTool gen, Value base); + public abstract Value generateAddress(NodeLIRGeneratorTool gen, Value base); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -56,8 +56,8 @@ } @Override - public void generate(LIRGeneratorTool generator) { - generator.emitMembar(barriers); + public void generate(NodeLIRGeneratorTool generator) { + generator.getLIRGeneratorTool().emitMembar(barriers); } public MemoryCheckpoint asMemoryCheckpoint() { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -40,7 +40,7 @@ } @Override - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { generator.emitNullCheck(object, this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -53,13 +53,16 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { Value address = location().generateAddress(gen, gen.operand(object())); - gen.setResult(this, gen.emitLoad(location().getValueKind(), address, this)); + gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(location().getValueKind(), address, this)); } @Override public Node canonical(CanonicalizerTool tool) { + if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { + return graph().add(new ReadNode(((PiNode) object()).getOriginalValue(), location(), stamp(), getGuard(), getBarrierType(), isCompressible())); + } return canonicalizeRead(this, location(), object(), tool, isCompressible()); } @@ -71,8 +74,14 @@ public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool, boolean compressible) { MetaAccessProvider metaAccess = tool.getMetaAccess(); if (read.usages().isEmpty()) { - // Read without usages can be safely removed. - return null; + GuardingNode guard = ((Access) read).getGuard(); + if (guard != null && !(guard instanceof FixedNode)) { + // The guard is necessary even if the read goes away. + return read.graph().add(new ValueAnchorNode((ValueNode) guard)); + } else { + // Read without usages or guard can be safely removed. + return null; + } } if (tool.canonicalizeReads()) { if (metaAccess != null && object != null && object.isConstant()) { @@ -80,7 +89,7 @@ location instanceof ConstantLocationNode) { long displacement = ((ConstantLocationNode) location).getDisplacement(); Kind kind = location.getValueKind(); - if (object.kind() == Kind.Object) { + if (object.getKind() == Kind.Object) { Object base = object.asConstant().asObject(); if (base != null) { Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, base, displacement, compressible); @@ -88,7 +97,7 @@ return ConstantNode.forConstant(constant, metaAccess, read.graph()); } } - } else if (object.kind().isNumericInteger()) { + } else if (object.getKind().isNumericInteger()) { long base = object.asConstant().asLong(); if (base != 0L) { Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, null, base + displacement, compressible); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -100,7 +100,7 @@ } @Override - public Value generateAddress(LIRGeneratorTool gen, Value base) { + public Value generateAddress(NodeLIRGeneratorTool gen, Value base) { throw new GraalInternalError("locationIdentity must be a constant so that this node can be canonicalized: " + locationIdentity); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -47,7 +47,7 @@ */ public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) { super(StampFactory.forVoid()); - assert value.kind() == Kind.Int || value.kind() == Kind.Long || value.kind() == Kind.Object : value.kind() + " key not supported by SwitchNode"; + assert value.getKind() == Kind.Int || value.getKind() == Kind.Long || value.getKind() == Kind.Object : value.getKind() + " key not supported by SwitchNode"; assert keySuccessors.length == keyProbabilities.length; this.successors = new NodeSuccessorList<>(this, successors); this.value = value; @@ -67,7 +67,7 @@ } protected boolean assertValues() { - Kind kind = value.kind(); + Kind kind = value.getKind(); for (int i = 0; i < keyCount(); i++) { Constant key = keyAt(i); assert key.getKind() == kind; diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -60,7 +60,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - assert kind() == Kind.Object && object.kind() == Kind.Object; + assert getKind() == Kind.Object && object.getKind() == Kind.Object; ObjectStamp my = (ObjectStamp) stamp(); ObjectStamp other = (ObjectStamp) object.stamp(); @@ -94,8 +94,8 @@ } @Override - public void generate(LIRGeneratorTool generator) { - assert kind() == Kind.Object && object.kind() == Kind.Object; + public void generate(NodeLIRGeneratorTool generator) { + assert getKind() == Kind.Object && object.getKind() == Kind.Object; /* * The LIR only cares about the kind of an operand, not the actual type of an object. So we * do not have to introduce a new operand. diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -65,7 +65,7 @@ int entryIndex = state.getVirtualObject().entryIndexForOffset(offset); if (entryIndex != -1) { ValueNode entry = state.getEntry(entryIndex); - if (entry.kind() == kind() || state.getVirtualObject().entryKind(entryIndex) == accessKind()) { + if (entry.getKind() == getKind() || state.getVirtualObject().entryKind(entryIndex) == accessKind()) { tool.replaceWith(entry); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -79,7 +79,7 @@ if (entryIndex != -1) { Kind entryKind = state.getVirtualObject().entryKind(entryIndex); ValueNode entry = state.getEntry(entryIndex); - if (entry.kind() == value.kind() || entryKind == accessKind()) { + if (entry.getKind() == value.getKind() || entryKind == accessKind()) { tool.setVirtualEntry(state, entryIndex, value(), true); tool.delete(); } else { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,16 +22,17 @@ */ package com.oracle.graal.nodes.extended; -import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; /** * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph. */ -public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Virtualizable, GuardingNode { +public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, GuardingNode { @Input private ValueNode anchored; @@ -41,7 +42,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { // Nothing to emit, since this node is used for structural purposes only. } @@ -50,19 +51,40 @@ } @Override - public Node canonical(CanonicalizerTool tool) { - if (anchored != null && !anchored.isConstant() && !(anchored instanceof FixedNode)) { - // Found entry that needs this anchor. - return this; + public void simplify(SimplifierTool tool) { + while (next() instanceof ValueAnchorNode) { + ValueAnchorNode nextAnchor = (ValueAnchorNode) next(); + if (nextAnchor.anchored == anchored || nextAnchor.anchored == null) { + // two anchors for the same anchored -> coalesce + // nothing anchored on the next anchor -> coalesce + nextAnchor.replaceAtUsages(this); + GraphUtil.removeFixedWithUnusedInputs(nextAnchor); + } else { + break; + } + } + if (usages().isEmpty() && next() instanceof FixedAccessNode) { + FixedAccessNode next = (FixedAccessNode) next(); + if (next.getGuard() == anchored) { + GraphUtil.removeFixedWithUnusedInputs(this); + return; + } else if (next.getGuard() == null && anchored instanceof GuardNode && ((GuardNode) anchored).condition() instanceof IsNullNode) { + // coalesce null check guards into subsequent read/write + next.setGuard((GuardingNode) anchored); + tool.addToWorkList(next()); + return; + } } - if (usages().isNotEmpty()) { - // A not uses this anchor => anchor is necessary. - return this; + if (anchored != null && (anchored.isConstant() || anchored instanceof FixedNode)) { + // anchoring fixed nodes and constants is useless + removeAnchoredNode(); } - // Anchor is not necessary any more => remove. - return null; + if (anchored == null && usages().isEmpty()) { + // anchor is not necessary any more => remove. + GraphUtil.removeFixedWithUnusedInputs(this); + } } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.LocationNode.Location; import com.oracle.graal.nodes.spi.*; @@ -33,7 +34,7 @@ /** * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}. */ -public final class WriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Virtualizable { +public final class WriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Simplifiable, Virtualizable { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -45,16 +46,6 @@ return stateAfter; } - @Override - public FrameState getState() { - if (stateAfter != null) { - assert super.getState() == null; - return stateAfter; - } else { - return super.getState(); - } - } - public void setStateAfter(FrameState x) { assert x == null || x.isAlive() : "frame state must be in a graph"; updateUsages(stateAfter, x); @@ -89,17 +80,24 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { Value address = location().generateAddress(gen, gen.operand(object())); // It's possible a constant was forced for other usages so inspect the value directly and // use a constant if it can be directly stored. Value v; - if (value().isConstant() && gen.canStoreConstant(value().asConstant(), isCompressible())) { + if (value().isConstant() && gen.getLIRGeneratorTool().canStoreConstant(value().asConstant(), isCompressible())) { v = value().asConstant(); } else { v = gen.operand(value()); } - gen.emitStore(location().getValueKind(), address, v, this); + gen.getLIRGeneratorTool().emitStore(location().getValueKind(), address, v, this); + } + + @Override + public void simplify(SimplifierTool tool) { + if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { + setObject(((PiNode) object()).getOriginalValue()); + } } @NodeIntrinsic diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -73,7 +73,7 @@ return; } } - for (Node usage : usages().snapshot()) { + for (Node usage : usages().distinct().snapshot()) { List snapshot = usage.inputs().snapshot(); graph().removeFixed((FixedWithNextNode) usage); for (Node input : snapshot) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,9 +33,9 @@ * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and * throws a {@link BailoutException} instead during graph building. */ -public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode { +public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode.DeoptBefore, DeoptimizingNode.DeoptAfter { - @Input private FrameState deoptState; + @Input private FrameState stateBefore; @Input private ValueNode object; @Input private MonitorIdNode monitorId; @@ -44,21 +44,14 @@ return true; } - @Override - public FrameState getDeoptimizationState() { - return deoptState; + public FrameState stateBefore() { + return stateBefore; } @Override - public void setDeoptimizationState(FrameState f) { - updateUsages(deoptState, f); - deoptState = f; - } - - @Override - public FrameState getState() { - assert deoptState == null || stateAfter() == null; - return deoptState == null ? stateAfter() : deoptState; + public void setStateBefore(FrameState f) { + updateUsages(stateBefore, f); + stateBefore = f; } public ValueNode object() { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -46,7 +46,7 @@ public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) { this.mirror = mirror; this.object = object; - assert mirror.kind() == Kind.Object : mirror.kind(); + assert mirror.getKind() == Kind.Object : mirror.getKind(); assert ObjectStamp.isExactType(mirror); assert ObjectStamp.typeOrNull(mirror).getName().equals("Ljava/lang/Class;"); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -61,7 +61,7 @@ public LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType, boolean compressible) { super(object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType, compressible); - assert expectedValue.kind() == newValue.kind(); + assert expectedValue.getKind() == newValue.getKind(); this.expectedValue = expectedValue; this.newValue = newValue; } @@ -72,7 +72,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.visitCompareAndSwap(this, location().generateAddress(gen, gen.operand(object()))); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -126,15 +126,28 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (!isStatic()) { + if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { + // attempt to devirtualize the call + + // check for trivial cases (e.g. final methods, nonvirtual methods) + if (targetMethod.canBeStaticallyBound()) { + invokeKind = InvokeKind.Special; + return this; + } + + // check if the exact type of the receiver can be determined ValueNode receiver = receiver(); - if (receiver != null && ObjectStamp.isExactType(receiver) && ObjectStamp.typeOrNull(receiver) != null) { - if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { - ResolvedJavaMethod method = ObjectStamp.typeOrNull(receiver).resolveMethod(targetMethod); - if (method != null) { - invokeKind = InvokeKind.Special; - targetMethod = method; - } + ResolvedJavaType exact = targetMethod.getDeclaringClass().asExactType(); + if (exact == null && ObjectStamp.isExactType(receiver)) { + exact = ObjectStamp.typeOrNull(receiver); + } + if (exact != null) { + // either the holder class is exact, or the receiver object has an exact type + ResolvedJavaMethod exactMethod = exact.resolveMethod(targetMethod); + if (exactMethod != null) { + invokeKind = InvokeKind.Special; + targetMethod = exactMethod; + return this; } } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -49,7 +49,7 @@ this.lockDepth = lockDepth; } - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { // nothing to do } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -34,7 +34,7 @@ * This node is used to perform the finalizer registration at the end of the java.lang.Object * constructor. */ -public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode { +public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter { public static final ForeignCallDescriptor REGISTER_FINALIZER = new ForeignCallDescriptor("registerFinalizer", void.class, Object.class); @@ -51,9 +51,9 @@ } @Override - public void generate(LIRGeneratorTool gen) { - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(REGISTER_FINALIZER); - gen.emitForeignCall(linkage, this, gen.operand(object())); + public void generate(NodeLIRGeneratorTool gen) { + ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(REGISTER_FINALIZER); + gen.getLIRGeneratorTool().emitForeignCall(linkage, this, gen.operand(object())); } @Override @@ -96,17 +96,6 @@ return true; } - @Override - public FrameState getDeoptimizationState() { - return deoptState; - } - - @Override - public void setDeoptimizationState(FrameState f) { - updateUsages(deoptState, f); - deoptState = f; - } - @SuppressWarnings("unused") @NodeIntrinsic public static void register(Object thisObj) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,7 +29,7 @@ import com.oracle.graal.graph.GraalInternalError; import com.oracle.graal.graph.NodeInputList; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.LIRGeneratorTool; +import com.oracle.graal.nodes.spi.NodeLIRGeneratorTool; import com.oracle.graal.nodes.spi.Lowerable; import com.oracle.graal.nodes.spi.LoweringTool; @@ -78,7 +78,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { throw GraalInternalError.shouldNotReachHere("should have replaced itself"); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -61,7 +61,7 @@ @Override public boolean isSorted() { - Kind kind = value().kind(); + Kind kind = value().getKind(); if (kind.isNumericInteger()) { Constant lastKey = null; for (int i = 0; i < keyCount(); i++) { @@ -92,7 +92,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { gen.emitSwitch(this); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -28,15 +28,12 @@ import com.oracle.graal.nodes.type.*; /** - * This interface can be used to generate LIR for arithmetic operations (@see - * ArithmeticLIRLowerable). + * This interface can be used to generate LIR for arithmetic operations. */ public interface ArithmeticLIRGenerator { - - Value operand(ValueNode object); - - Value setResult(ValueNode x, Value operand); - + /** + * TODO remove reference to {@link Stamp}. + */ PlatformKind getPlatformKind(Stamp stamp); Value emitNegate(Value input); @@ -47,12 +44,24 @@ Value emitMul(Value a, Value b); + /** + * TODO remove {@link DeoptimizeNode}. + */ Value emitDiv(Value a, Value b, DeoptimizingNode deopting); + /** + * TODO remove {@link DeoptimizeNode}. + */ Value emitRem(Value a, Value b, DeoptimizingNode deopting); + /** + * TODO remove {@link DeoptimizeNode}. + */ Value emitUDiv(Value a, Value b, DeoptimizingNode deopting); + /** + * TODO remove {@link DeoptimizeNode}. + */ Value emitURem(Value a, Value b, DeoptimizingNode deopting); Value emitNot(Value input); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRLowerable.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,5 +26,5 @@ public interface ArithmeticLIRLowerable extends ArithmeticOperation { - void generate(ArithmeticLIRGenerator gen); + void generate(NodeLIRGeneratorTool gen); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Sun Mar 30 16:08:33 2014 +0200 @@ -25,9 +25,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; public interface LIRGeneratorTool extends ArithmeticLIRGenerator { @@ -39,6 +37,14 @@ ForeignCallsProvider getForeignCalls(); + Value emitLoad(Kind kind, Value address, Access access); + + void emitStore(Kind kind, Value address, Value input, Access access); + + void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting); + + Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args); + /** * Checks whether the supplied constant can be used without loading it into a register for most * operations, i.e., for commonly used arithmetic, logical, and comparison operations. @@ -59,47 +65,20 @@ void emitMove(AllocatableValue dst, Value src); + /** + * Emits an op that loads the address of some raw data. + * + * @param dst the variable into which the address is loaded + * @param data the data to be installed with the generated code + */ + void emitData(AllocatableValue dst, byte[] data); + Value emitAddress(Value base, long displacement, Value index, int scale); Value emitAddress(StackSlot slot); - Value emitLoad(Kind kind, Value address, Access access); - - void emitStore(Kind kind, Value address, Value input, Access access); - void emitMembar(int barriers); - void emitDeoptimize(Value actionAndReason, Value failedSpeculation, DeoptimizingNode deopting); - - void emitNullCheck(ValueNode v, DeoptimizingNode deopting); - - Value emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args); - - void emitIf(IfNode i); - - void emitConditional(ConditionalNode i); - - void emitSwitch(SwitchNode i); - - void emitInvoke(Invoke i); - - // Handling of block-end nodes still needs to be unified in the LIRGenerator. - void visitMerge(MergeNode i); - - void visitEndNode(AbstractEndNode i); - - void visitLoopEnd(LoopEndNode i); - - void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address); - - // These methods define the contract a runtime specific backend must provide. - - void visitReturn(ReturnNode i); - - void visitSafepointNode(SafepointNode i); - - void visitBreakpointNode(BreakpointNode i); - void emitUnwind(Value operand); /** @@ -108,5 +87,7 @@ */ void beforeRegisterAllocation(); - void visitInfopointNode(InfopointNode i); + void emitIncomingValues(Value[] params); + + void emitReturn(Value input); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRLowerable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRLowerable.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRLowerable.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,5 +24,5 @@ public interface LIRLowerable { - void generate(LIRGeneratorTool generator); + void generate(NodeLIRGeneratorTool generator); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,42 @@ +/* + * 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.nodes.spi; + +import com.oracle.graal.nodes.extended.*; + +/** + * Marks nodes which may be lowered in combination with a memory operation. + */ +public interface MemoryArithmeticLIRLowerable { + + /** + * Attempt to generate a memory form of a node operation. On platforms that support it this will + * be called when the merging is safe. + * + * @param gen + * @param access the memory input which can potentially merge into this operation. + * @return null if it's not possible to emit a memory form of this operation. A non-null value + * will be set as the operand of this node. + */ + boolean generate(MemoryArithmeticLIRLowerer gen, Access access); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,71 @@ +/* + * 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.nodes.spi; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; + +/** + * This interface can be used to generate LIR for arithmetic operations where one of the operations + * is load (@see ArithmeticLIRLowerable). + */ +public interface MemoryArithmeticLIRLowerer { + + Value setResult(ValueNode x, Value operand); + + Value emitAddMemory(ValueNode x, ValueNode y, Access access); + + Value emitMulMemory(ValueNode x, ValueNode y, Access access); + + Value emitSubMemory(ValueNode x, ValueNode y, Access access); + + Value emitDivMemory(ValueNode x, ValueNode y, Access access); + + Value emitRemMemory(ValueNode x, ValueNode y, Access access); + + Value emitXorMemory(ValueNode x, ValueNode y, Access access); + + Value emitOrMemory(ValueNode x, ValueNode y, Access access); + + Value emitAndMemory(ValueNode x, ValueNode y, Access access); + + Value emitReinterpretMemory(Stamp stamp, Access access); + + Value emitSignExtendMemory(Access access, int fromBits, int toBits); + + Value emitNarrowMemory(int resultBits, Access access); + + Value emitZeroExtendMemory(int inputBits, int resultBits, Access access); + + Value emitFloatConvertMemory(FloatConvert op, Access access); + + boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List deferred); + + boolean emitIfMemory(IfNode ifNode, Access access); + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRGeneratorTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeLIRGeneratorTool.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.spi; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; + +public interface NodeLIRGeneratorTool extends NodeMappableLIRGenerator { + + void emitNullCheck(ValueNode v, DeoptimizingNode deopting); + + void emitIf(IfNode i); + + void emitConditional(ConditionalNode i); + + void emitSwitch(SwitchNode i); + + void emitInvoke(Invoke i); + + // Handling of block-end nodes still needs to be unified in the LIRGenerator. + void visitMerge(MergeNode i); + + void visitEndNode(AbstractEndNode i); + + void visitLoopEnd(LoopEndNode i); + + void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address); + + // These methods define the contract a runtime specific backend must provide. + + void visitReturn(ReturnNode i); + + void visitSafepointNode(SafepointNode i); + + void visitBreakpointNode(BreakpointNode i); + + void visitInfopointNode(InfopointNode i); + + LIRGeneratorTool getLIRGeneratorTool(); + + void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, double probability); + + Value[] visitInvokeArguments(CallingConvention cc, Collection arguments); + + MemoryArithmeticLIRLowerer getMemoryLowerer(); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeMappableLIRGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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.nodes.spi; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; + +public interface NodeMappableLIRGenerator { + + Value operand(ValueNode object); + + boolean hasOperand(ValueNode object); + + Value setResult(ValueNode x, Value operand); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,25 +24,11 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import static com.oracle.graal.nodes.StructuredGraph.GuardsStage.*; /** * Interface for nodes which have {@link FrameState} nodes as input. - *

    - * Some node can implement more than one interface which requires a {@link FrameState} input (e.g. - * {@link DeoptimizingNode} and {@link StateSplit}). Since this interface can only report one - * FrameState, such nodes must ensure they only maintain a link to at most one FrameState at all - * times. Usually this is not a problem because FrameStates are associated only with StateSplit - * nodes before the {@link #AFTER_FSA} stage and only with DeoptimizingNodes after. - * */ public interface NodeWithState { - /** - * Gets the {@link FrameState} associated with this node. - * - * @return the {@link FrameState} associated with this node - */ - FrameState getState(); Node asNode(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Sun Mar 30 16:08:33 2014 +0200 @@ -462,4 +462,41 @@ } return v; } + + /** + * Compute the stamp resulting from the unsigned comparison being true. + * + * @return null if it's can't be true or it nothing useful can be encoded. + */ + public static Stamp unsignedCompare(Stamp stamp, Stamp stamp2) { + IntegerStamp x = (IntegerStamp) stamp; + IntegerStamp y = (IntegerStamp) stamp2; + if (x == x.unrestricted() && y == y.unrestricted()) { + // Don't know anything. + return null; + } + // c <| n, where c is a constant and n is known to be positive. + if (x.lowerBound() == x.upperBound()) { + if (y.isPositive()) { + if (x.lowerBound() == (1 << x.getBits()) - 1) { + // Constant is MAX_VALUE which must fail. + return null; + } + if (x.lowerBound() <= y.lowerBound()) { + // Test will fail. Return illegalStamp instead? + return null; + } + // If the test succeeds then this proves that n is at greater than c so the bounds + // are [c+1..-n.upperBound)]. + return StampFactory.forInteger(x.getBits(), false, x.lowerBound() + 1, y.upperBound()); + } + return null; + } + // n <| c, where c is a strictly positive constant + if (y.lowerBound() == y.upperBound() && y.isStrictlyPositive()) { + // The test proves that n is positive and less than c, [0..c-1] + return StampFactory.forInteger(y.getBits(), false, 0, y.lowerBound() - 1); + } + return null; + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -56,7 +56,7 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { // nothing to do... } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -91,7 +91,7 @@ public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks); @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { // nothing to do... } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Sun Mar 30 16:08:33 2014 +0200 @@ -45,10 +45,14 @@ * } * */ -@SupportedSourceVersion(SourceVersion.RELEASE_7) @SupportedAnnotationTypes({"com.oracle.graal.options.Option"}) public class OptionProcessor extends AbstractProcessor { + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + private final Set processed = new HashSet<>(); private void processElement(Element element, OptionsInfo info) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Sun Mar 30 16:08:33 2014 +0200 @@ -38,7 +38,7 @@ *

    * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be * used: - * + * *

          * try (OverrideScope s = OptionValue.override(myOption, myValue) {
          *     // code that depends on myOption == myValue
    @@ -65,7 +65,7 @@
          * 

    * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be * used: - * + * *

          * Map overrides = new HashMap<>();
          * overrides.put(myOption1, myValue1);
    @@ -96,13 +96,13 @@
          * 

    * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be * used: - * + * *

          * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) {
          *     // code that depends on myOption == myValue
          * }
          * 
    - * + * * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]} */ public static OverrideScope override(Object... overrides) { @@ -221,14 +221,14 @@ /** * Gets the values of this option including overridden values. - * + * * @param c the collection to which the values are added. If null, one is allocated. * @return the collection to which the values were added in order from most overridden to * current value */ @SuppressWarnings("unchecked") public Collection getValues(Collection c) { - Collection values = c == null ? new ArrayList() : c; + Collection values = c == null ? new ArrayList<>() : c; if (!(this instanceof StableOptionValue)) { OverrideScope overrideScope = overrideScopes.get(); if (overrideScope != null) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -273,10 +273,10 @@ // @formatter:on private boolean performReplacement(final Node node, Node canonical) { if (canonical == node) { - Debug.log("Canonicalizer: work on %s", node); + Debug.log("Canonicalizer: work on %1s", node); return false; } else { - Debug.log("Canonicalizer: replacing %s with %s", node, canonical); + Debug.log("Canonicalizer: replacing %1s with %1s", node, canonical); METRIC_CANONICALIZED_NODES.increment(); StructuredGraph graph = (StructuredGraph) node.graph(); if (node instanceof FloatingNode) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; @@ -63,7 +64,40 @@ @Override protected void run(StructuredGraph inputGraph) { graph = inputGraph; - new ConditionalElimination(graph.start(), new State()).apply(); + try (Scope s = Debug.scope("ConditionalElimination")) { + new ConditionalElimination(graph.start(), new State()).apply(); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + /** + * Type information about a {@code value} that it produced by a {@code guard}. Usage of the + * stamp information requires adopting the guard. Usually this means replacing an existing guard + * with this guard. + */ + static class GuardedStamp { + private final ValueNode value; + private final Stamp stamp; + private final GuardNode guard; + + GuardedStamp(ValueNode value, Stamp stamp, GuardNode guard) { + this.value = value; + this.stamp = stamp; + this.guard = guard; + } + + public Stamp getStamp() { + return stamp; + } + + public GuardNode getGuard() { + return guard; + } + + public ValueNode getValue() { + return value; + } } public static class State extends MergeableState implements Cloneable { @@ -73,6 +107,7 @@ private HashSet knownNull; private IdentityHashMap trueConditions; private IdentityHashMap falseConditions; + private IdentityHashMap valueConstraints; public State() { this.knownTypes = new IdentityHashMap<>(); @@ -80,6 +115,7 @@ this.knownNull = new HashSet<>(); this.trueConditions = new IdentityHashMap<>(); this.falseConditions = new IdentityHashMap<>(); + this.valueConstraints = new IdentityHashMap<>(); } public State(State other) { @@ -88,6 +124,7 @@ this.knownNull = new HashSet<>(other.knownNull); this.trueConditions = new IdentityHashMap<>(other.trueConditions); this.falseConditions = new IdentityHashMap<>(other.falseConditions); + this.valueConstraints = new IdentityHashMap<>(other.valueConstraints); } @Override @@ -95,6 +132,7 @@ IdentityHashMap newKnownTypes = new IdentityHashMap<>(); IdentityHashMap newTrueConditions = new IdentityHashMap<>(); IdentityHashMap newFalseConditions = new IdentityHashMap<>(); + IdentityHashMap newValueConstraints = new IdentityHashMap<>(); HashSet newKnownNull = new HashSet<>(knownNull); HashSet newKnownNonNull = new HashSet<>(knownNonNull); @@ -159,7 +197,7 @@ // this piece of code handles phis if (!(merge instanceof LoopBeginNode)) { for (PhiNode phi : merge.phis()) { - if (phi.type() == PhiType.Value && phi.kind() == Kind.Object) { + if (phi.type() == PhiType.Value && phi.getKind() == Kind.Object) { ValueNode firstValue = phi.valueAt(0); ResolvedJavaType type = getNodeType(firstValue); boolean nonNull = knownNonNull.contains(firstValue); @@ -191,6 +229,7 @@ this.knownNull = newKnownNull; this.trueConditions = newTrueConditions; this.falseConditions = newFalseConditions; + this.valueConstraints = newValueConstraints; return true; } @@ -404,32 +443,145 @@ } } - private void registerGuard(GuardNode guard) { + private GuardedStamp computeGuardedStamp(GuardNode guard) { + if (guard.condition() instanceof IntegerBelowThanNode) { + if (guard.negated()) { + // Not sure how to reason about negated guards + return null; + } + IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition(); + if (below.x().getKind() == Kind.Int && below.x().isConstant() && !below.y().isConstant()) { + Stamp stamp = StampTool.unsignedCompare(below.x().stamp(), below.y().stamp()); + if (stamp != null) { + return new GuardedStamp(below.y(), stamp, guard); + } + } + if (below.y().getKind() == Kind.Int && below.y().isConstant() && !below.x().isConstant()) { + Stamp stamp = StampTool.unsignedCompare(below.x().stamp(), below.y().stamp()); + if (stamp != null) { + return new GuardedStamp(below.x(), stamp, guard); + } + } + } + return null; + } + + private boolean eliminateTrivialGuard(GuardNode guard) { LogicNode condition = guard.condition(); ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition); if (existingGuards != null) { - guard.replaceAtUsages(existingGuards); - GraphUtil.killWithUnusedFloatingInputs(guard); - metricGuardsRemoved.increment(); + eliminateGuard(guard, existingGuards); + return true; } else { ValueNode anchor = state.trueConditions.get(condition); if (anchor != null) { if (!guard.negated()) { - guard.replaceAtUsages(anchor); - metricGuardsRemoved.increment(); - GraphUtil.killWithUnusedFloatingInputs(guard); + eliminateGuard(guard, anchor); + return true; } } else { anchor = state.falseConditions.get(condition); if (anchor != null) { if (guard.negated()) { - guard.replaceAtUsages(anchor); - metricGuardsRemoved.increment(); - GraphUtil.killWithUnusedFloatingInputs(guard); + eliminateGuard(guard, anchor); + return true; } + } + } + } + // Can't be eliminated so accumulate any type information from the guard + registerConditionalStamp(guard); + return false; + } + + /** + * Replace {@code guard} with {@code anchor} . + * + * @param guard The guard to eliminate. + * @param anchor Node to replace the guard. + */ + private void eliminateGuard(GuardNode guard, ValueNode anchor) { + guard.replaceAtUsages(anchor); + metricGuardsRemoved.increment(); + GraphUtil.killWithUnusedFloatingInputs(guard); + } + + /** + * See if a conditional type constraint can prove this guard. + * + * @param guard + * @return true if the guard was eliminated. + */ + private boolean testImpliedGuard(GuardNode guard) { + if (state.valueConstraints.size() == 0) { + // Nothing to do. + return false; + } + + GuardNode existingGuard = null; + if (guard.condition() instanceof IntegerBelowThanNode) { + IntegerBelowThanNode below = (IntegerBelowThanNode) guard.condition(); + IntegerStamp xStamp = (IntegerStamp) below.x().stamp(); + IntegerStamp yStamp = (IntegerStamp) below.y().stamp(); + GuardedStamp cstamp = state.valueConstraints.get(below.x()); + if (cstamp != null) { + xStamp = (IntegerStamp) cstamp.getStamp(); + } else { + cstamp = state.valueConstraints.get(below.y()); + if (cstamp != null) { + yStamp = (IntegerStamp) cstamp.getStamp(); + } + } + if (cstamp != null) { + if (cstamp.getGuard() == guard) { + // found ourselves + return false; + } + // See if we can use the other guard + if (!guard.negated() && !cstamp.getGuard().negated() && yStamp.isPositive()) { + if (xStamp.isPositive() && xStamp.upperBound() < yStamp.lowerBound()) { + // Proven true + existingGuard = cstamp.getGuard(); + Debug.log("existing guard %s %1s proves %1s", existingGuard, existingGuard.condition(), guard.condition()); + } else if (xStamp.isStrictlyNegative() || xStamp.lowerBound() >= yStamp.upperBound()) { + // An earlier guard proves that this will always fail but it's probably + // not worth trying to use it. + } + } + } + } + + if (existingGuard != null) { + // Found a guard which proves this guard to be true, so replace it. + eliminateGuard(guard, existingGuard); + return true; + } + return false; + } + + private void registerConditionalStamp(GuardNode guard) { + GuardedStamp conditional = computeGuardedStamp(guard); + if (conditional != null) { + GuardedStamp other = state.valueConstraints.get(conditional.getValue()); + if (other == null) { + state.valueConstraints.put(conditional.getValue(), conditional); + } else if (guard.negated() != other.getGuard().negated()) { + // This seems impossible + // Debug.log("negated and !negated guards %1s %1s", guard, other.getGuard()); + } else if (!guard.negated()) { + // two different constraints, pick the one with the tightest type + // information + Stamp result = conditional.getStamp().join(other.getStamp()); + if (result == conditional.getStamp()) { + Debug.log("%1s overrides existing value %1s", guard.condition(), other.getGuard().condition()); + state.valueConstraints.put(conditional.getValue(), conditional); + } else if (result == other.getStamp()) { + // existing type constraint is best + Debug.log("existing value is best %s", other.getGuard()); } else { - registerCondition(!guard.negated(), condition, guard); + // The merger produced some combination of values + Debug.log("type merge produced new type %s", result); } } } @@ -494,8 +646,29 @@ if (pred != null) { registerControlSplitInfo(pred, begin); } + + // First eliminate any guards which can be trivially removed and register any + // type constraints the guards produce. for (GuardNode guard : begin.guards().snapshot()) { - registerGuard(guard); + eliminateTrivialGuard(guard); + } + + // Collect the guards which have produced conditional stamps. + HashSet provers = new HashSet<>(); + for (Map.Entry e : state.valueConstraints.entrySet()) { + provers.add(e.getValue().getGuard()); + } + + // Process the remaining guards. Guards which produced some type constraint should + // just be registered since they aren't trivially deleteable. Test the other guards + // to see if they can be deleted using type constraints. + for (GuardNode guard : begin.guards().snapshot()) { + if (provers.contains(guard) || !testImpliedGuard(guard)) { + registerCondition(!guard.negated(), guard.condition(), guard); + } + } + for (GuardNode guard : provers) { + assert !testImpliedGuard(guard) : "provers shouldn't be trivially eliminatable"; } } else if (node instanceof FixedGuardNode) { FixedGuardNode guard = (FixedGuardNode) node; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -88,6 +88,9 @@ } for (int i = 0; i < mergePredecessors.size(); ++i) { AbstractEndNode mergePredecessor = mergePredecessors.get(i); + if (!mergePredecessor.isAlive()) { + break; + } if (xs[i] == null) { continue; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -82,7 +82,7 @@ } } if (obsoletes != null) { - ((DynamicDeoptimizeNode) ((MergeNode) target).next()).setDeoptimizationState(fs); + ((DynamicDeoptimizeNode) ((MergeNode) target).next()).setStateBefore(fs); for (AbstractDeoptimizeNode obsolete : obsoletes) { obsolete.safeDelete(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -49,24 +49,41 @@ @Override protected FrameState processNode(FixedNode node, FrameState currentState) { - if (node instanceof DeoptimizingNode) { - DeoptimizingNode deopt = (DeoptimizingNode) node; - if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) { + if (node instanceof DeoptimizingNode.DeoptBefore) { + DeoptimizingNode.DeoptBefore deopt = (DeoptimizingNode.DeoptBefore) node; + if (deopt.canDeoptimize() && deopt.stateBefore() == null) { GraalInternalError.guarantee(currentState != null, "no FrameState at DeoptimizingNode %s", deopt); - deopt.setDeoptimizationState(currentState); + deopt.setStateBefore(currentState); } } + FrameState newState = currentState; if (node instanceof StateSplit) { StateSplit stateSplit = (StateSplit) node; FrameState stateAfter = stateSplit.stateAfter(); if (stateAfter != null) { - FrameState newState = stateAfter; + newState = stateAfter; stateSplit.setStateAfter(null); - return newState; } } - return currentState; + + if (node instanceof DeoptimizingNode.DeoptDuring) { + DeoptimizingNode.DeoptDuring deopt = (DeoptimizingNode.DeoptDuring) node; + if (deopt.canDeoptimize()) { + GraalInternalError.guarantee(newState != null, "no FrameState at DeoptimizingNode %s", deopt); + deopt.computeStateDuring(newState); + } + } + + if (node instanceof DeoptimizingNode.DeoptAfter) { + DeoptimizingNode.DeoptAfter deopt = (DeoptimizingNode.DeoptAfter) node; + if (deopt.canDeoptimize() && deopt.stateAfter() == null) { + GraalInternalError.guarantee(newState != null, "no FrameState at DeoptimizingNode %s", deopt); + deopt.setStateAfter(newState); + } + } + + return newState; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -55,6 +55,9 @@ * does the actual control-flow expansion of the remaining {@link GuardNode GuardNodes}. */ public class GuardLoweringPhase extends BasePhase { + + private static final DebugMetric metricImplicitNullCheck = Debug.metric("ImplicitNullCheck"); + private static class UseImplicitNullChecks extends ScheduledNodeIterator { private final IdentityHashMap nullGuarded = new IdentityHashMap<>(); @@ -88,6 +91,7 @@ private void processAccess(Access access) { GuardNode guard = nullGuarded.get(access.object()); if (guard != null && isImplicitNullCheck(access.nullCheckLocation())) { + metricImplicitNullCheck.increment(); access.setGuard(guard.getGuard()); FixedAccessNode fixedAccess; if (access instanceof FloatingAccessNode) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Sun Mar 30 16:08:33 2014 +0200 @@ -173,7 +173,10 @@ public static void logInliningDecision(final String msg, final Object... args) { try (Scope s = Debug.scope(inliningDecisionsScopeString)) { - Debug.log(msg, args); + // Can't use log here since we are varargs + if (Debug.isLogEnabled()) { + Debug.logv(msg, args); + } } } @@ -482,7 +485,7 @@ private void createGuard(StructuredGraph graph, MetaAccessProvider metaAccess) { ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke); ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), metaAccess, graph); - LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.kind(), null)); + LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.getKind(), null)); CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub); FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); @@ -624,7 +627,7 @@ returnMerge.setStateAfter(invoke.stateAfter()); PhiNode returnValuePhi = null; - if (invoke.asNode().kind() != Kind.Void) { + if (invoke.asNode().getKind() != Kind.Void) { returnValuePhi = graph.addWithoutUnique(new PhiNode(invoke.asNode().stamp().unrestricted(), returnMerge)); } @@ -812,7 +815,7 @@ FixedNode lastSucc = successors[concretes.size()]; for (int i = concretes.size() - 1; i >= 0; --i) { - LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].kind())); + LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].getKind())); CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]); IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i])); method.setNext(ifNode); @@ -910,7 +913,7 @@ result.asNode().replaceFirstInput(result.callTarget(), callTarget); result.setUseForInlining(useForInlining); - Kind kind = invoke.asNode().kind(); + Kind kind = invoke.asNode().getKind(); if (kind != Kind.Void) { FrameState stateAfter = invoke.stateAfter(); stateAfter = stateAfter.duplicate(stateAfter.bci); @@ -1314,7 +1317,7 @@ assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal(); assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase"; - Kind returnKind = invokeNode.kind(); + Kind returnKind = invokeNode.getKind(); FrameState stateAfter = invoke.stateAfter(); assert stateAfter == null || stateAfter.isAlive(); @@ -1431,7 +1434,7 @@ if (frameState.outerFrameState() == null) { assert frameState.bci == FrameState.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()); if (outerFrameState == null) { - outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.kind()); + outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.getKind()); outerFrameState.setDuringCall(true); } frameState.setOuterFrameState(outerFrameState); @@ -1515,7 +1518,7 @@ assert !callTarget.isStatic() : callTarget.targetMethod(); StructuredGraph graph = callTarget.graph(); ValueNode firstParam = callTarget.arguments().get(0); - if (firstParam.kind() == Kind.Object && !ObjectStamp.isObjectNonNull(firstParam)) { + if (firstParam.getKind() == Kind.Object && !ObjectStamp.isObjectNonNull(firstParam)) { IsNullNode condition = graph.unique(new IsNullNode(firstParam)); Stamp stamp = firstParam.stamp().join(objectNonNull()); GuardingPiNode nonNullReceiver = graph.add(new GuardingPiNode(firstParam, condition, true, NullCheckException, InvalidateReprofile, stamp)); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.phases.common; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.schedule.*; + +/** + * This phase add counters for the dynamically executed number of nodes. Incrementing the counter + * for each node would be too costly, so this phase takes the compromise that it trusts split + * probabilities, but not loop frequencies. This means that it will insert counters at the start of + * a method and at each loop header. + * + * A schedule is created so that floating nodes can also be taken into account. The weight of a node + * is determined heuristically in the + * {@link ProfileCompiledMethodsPhase#getNodeWeight(ScheduledNode)} method. + * + * Additionally, there's a second counter that's only increased for code sections without invokes. + */ +public class ProfileCompiledMethodsPhase extends Phase { + + private static final String GROUP_NAME = "~profiled weight"; + private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)"; + + private static final boolean WITH_SECTION_HEADER = false; + + @Override + protected void run(StructuredGraph graph) { + ComputeProbabilityClosure closure = new ComputeProbabilityClosure(graph); + NodesToDoubles probabilities = closure.apply(); + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph, false); + + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); + for (Loop loop : cfg.getLoops()) { + double loopProbability = probabilities.get(loop.loopBegin()); + if (loopProbability > (1D / Integer.MAX_VALUE)) { + addSectionCounters(loop.loopBegin(), loop.blocks, loop.children, schedule, probabilities); + } + } + addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), Arrays.asList(cfg.getLoops()), schedule, probabilities); + } + + private static void addSectionCounters(FixedWithNextNode start, Collection sectionBlocks, Collection childLoops, SchedulePhase schedule, NodesToDoubles probabilities) { + HashSet blocks = new HashSet<>(sectionBlocks); + for (Loop loop : childLoops) { + blocks.removeAll(loop.blocks); + } + double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start); + DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next()); + if (!hasInvoke(blocks)) { + DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next()); + } + } + + private static String sectionHead(Node node) { + if (WITH_SECTION_HEADER) { + return node.toString(); + } else { + return ""; + } + } + + private static double getSectionWeight(SchedulePhase schedule, NodesToDoubles probabilities, Collection blocks) { + double count = 0; + for (Block block : blocks) { + double blockProbability = probabilities.get(block.getBeginNode()); + for (ScheduledNode node : schedule.getBlockToNodesMap().get(block)) { + count += blockProbability * getNodeWeight(node); + } + } + return count; + } + + private static double getNodeWeight(ScheduledNode node) { + if (node instanceof MergeNode) { + return ((MergeNode) node).phiPredecessorCount(); + } else if (node instanceof AbstractBeginNode || node instanceof AbstractEndNode || node instanceof MonitorIdNode || node instanceof ConstantNode || node instanceof ParameterNode || + node instanceof CallTargetNode || node instanceof ValueProxy || node instanceof VirtualObjectNode || node instanceof ReinterpretNode) { + return 0; + } else if (node instanceof AccessMonitorNode) { + return 10; + } else if (node instanceof Access) { + return 2; + } else if (node instanceof LogicNode || node instanceof ConvertNode || node instanceof BinaryNode || node instanceof NotNode) { + return 1; + } else if (node instanceof IntegerDivNode || node instanceof FloatDivNode || node instanceof IntegerRemNode || node instanceof FloatRemNode) { + return 10; + } else if (node instanceof IntegerMulNode || node instanceof FloatMulNode) { + return 3; + } else if (node instanceof Invoke) { + return 5; + } else if (node instanceof IfNode || node instanceof SafepointNode) { + return 1; + } else if (node instanceof SwitchNode) { + return node.successors().count(); + } else if (node instanceof ReturnNode || node instanceof UnwindNode || node instanceof DeoptimizeNode) { + return node.successors().count(); + } else if (node instanceof AbstractNewObjectNode) { + return 10; + } + return 2; + } + + private static boolean hasInvoke(Collection blocks) { + boolean hasInvoke = false; + for (Block block : blocks) { + for (FixedNode fixed : block.getNodes()) { + if (fixed instanceof Invoke) { + hasInvoke = true; + } + } + } + return hasInvoke; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -76,7 +76,7 @@ AbstractBeginNode nonTrappingContinuation = ifNode.falseSuccessor(); AbstractBeginNode trappingContinuation = ifNode.trueSuccessor(); NullCheckNode trappingNullCheck = deopt.graph().add(new NullCheckNode(isNullNode.object())); - trappingNullCheck.setDeoptimizationState(deopt.getDeoptimizationState()); + trappingNullCheck.setStateBefore(deopt.stateBefore()); deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation); GraphUtil.killCFG(trappingContinuation); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -36,38 +36,7 @@ */ public abstract class BasePhase { - /** - * Phase name lazily computed from the phase class. - */ - class Name extends LazyName { - - @Override - public String createString() { - String s = BasePhase.this.getClass().getSimpleName(); - if (s.endsWith("Phase")) { - return s.substring(0, s.length() - "Phase".length()); - } - return s; - } - } - - /** - * Lazily computed debug value name composed of a prefix and a phase's name. - */ - class DebugValueName extends LazyName { - final String prefix; - - public DebugValueName(String prefix) { - this.prefix = prefix; - } - - @Override - public String createString() { - return prefix + name; - } - } - - private final CharSequence name; + private CharSequence name; private final DebugTimer phaseTimer; private final DebugMetric phaseMetric; @@ -80,17 +49,15 @@ } protected BasePhase() { - name = new Name(); - assert checkName(name.toString()); - phaseTimer = Debug.timer(new DebugValueName("PhaseTime_")); - phaseMetric = Debug.metric(new DebugValueName("PhaseCount_")); + phaseTimer = Debug.timer("PhaseTime_%s", getClass()); + phaseMetric = Debug.metric("PhaseCount_%s", getClass()); } protected BasePhase(String name) { assert checkName(name); this.name = name; - phaseTimer = Debug.timer(new DebugValueName("PhaseTime_")); - phaseMetric = Debug.metric(new DebugValueName("PhaseCount_")); + phaseTimer = Debug.timer("PhaseTime_%s", getClass()); + phaseMetric = Debug.metric("PhaseCount_%s", getClass()); } protected CharSequence getDetailedName() { @@ -102,11 +69,11 @@ } public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { - try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(name, this)) { + try (TimerCloseable a = phaseTimer.start(); Scope s = Debug.scope(getClass(), this)) { BasePhase.this.run(graph, context); phaseMetric.increment(); if (dumpGraph) { - Debug.dump(graph, "After phase %s", name); + Debug.dump(graph, "After phase %s", getName()); } assert graph.verify(); } catch (Throwable t) { @@ -115,6 +82,13 @@ } public final CharSequence getName() { + if (name == null) { + String s = BasePhase.this.getClass().getSimpleName(); + if (s.endsWith("Phase")) { + s = s.substring(0, s.length() - "Phase".length()); + } + name = s; + } return name; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Sun Mar 30 16:08:33 2014 +0200 @@ -271,6 +271,8 @@ public static final OptionValue OptDevirtualizeInvokesOptimistically = new OptionValue<>(true); @Option(help = "") public static final OptionValue OptPushThroughPi = new OptionValue<>(true); + @Option(help = "Allow backend to emit arithmetic and compares directly against memory.") + public static final OptionValue OptFoldMemory = new OptionValue<>(true); /** diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/LazyName.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/LazyName.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/LazyName.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,8 +26,8 @@ /** * A name whose {@link String} value is computed only when it is needed. This is useful in - * combination with debugging facilities such as {@link Debug#scope(CharSequence, Object...)} where - * the {@link String} value of a name is only needed if debugging is enabled. + * combination with debugging facilities such as {@link Debug#scope(Object)} where the + * {@link String} value of a name is only needed if debugging is enabled. */ public abstract class LazyName implements CharSequence { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.graal.debug.internal.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.util.*; @@ -64,98 +63,14 @@ } public NodesToDoubles apply() { - adjustControlSplitProbabilities(); + // adjustControlSplitProbabilities(); new PropagateProbability(graph.start()).apply(); computeLoopFactors(); new PropagateLoopFrequency(graph.start()).apply(); - assert verifyProbabilities(); + // assert verifyProbabilities(); return nodeProbabilities; } - /** - * Assume that paths with a DeoptimizeNode at their end are taken infrequently. - */ - private void adjustControlSplitProbabilities() { - Set result = new ArraySet<>(); - NodeBitMap visitedNodes = new NodeBitMap(graph); - for (AbstractDeoptimizeNode n : graph.getNodes(AbstractDeoptimizeNode.class)) { - if (!(n instanceof DeoptimizeNode) || ((DeoptimizeNode) n).action().doesInvalidateCompilation()) { - findParentControlSplitNodes(result, n, visitedNodes); - } - } - - for (ControlSplitNode n : result) { - if (!allSuxVisited(n, visitedNodes)) { - modifyProbabilities(n, visitedNodes); - } - } - } - - private static void findParentControlSplitNodes(Set result, AbstractDeoptimizeNode n, NodeBitMap visitedNodes) { - ArrayDeque nodes = new ArrayDeque<>(); - nodes.push(n); - - Node currentNode; - do { - currentNode = nodes.pop(); - visitedNodes.mark(currentNode); - - for (Node pred : currentNode.cfgPredecessors()) { - FixedNode fixedPred = (FixedNode) pred; - if (visitedNodes.isMarked(fixedPred) && allPredsVisited(fixedPred, visitedNodes)) { - DebugScope.dump(n.graph(), "ComputeProbabilityClosure"); - GraalInternalError.shouldNotReachHere(String.format("Endless loop because %s was already visited", fixedPred)); - } else if (allSuxVisited(fixedPred, visitedNodes)) { - nodes.push(fixedPred); - } else { - assert fixedPred instanceof ControlSplitNode : "only control splits can have more than one sux"; - result.add((ControlSplitNode) fixedPred); - } - } - } while (!nodes.isEmpty()); - } - - private static void modifyProbabilities(ControlSplitNode controlSplit, NodeBitMap visitedNodes) { - assert !allSuxVisited(controlSplit, visitedNodes); - for (Node sux : controlSplit.successors()) { - if (visitedNodes.isMarked(sux)) { - controlSplit.setProbability((AbstractBeginNode) sux, 0); - } - } - } - - private static boolean allSuxVisited(FixedNode node, NodeBitMap visitedNodes) { - return allVisited(node.successors(), visitedNodes); - } - - private static boolean allPredsVisited(FixedNode node, NodeBitMap visitedNodes) { - return allVisited(node.cfgPredecessors(), visitedNodes); - } - - private static boolean allVisited(Iterable nodes, NodeBitMap visitedNodes) { - for (Node sux : nodes) { - if (!visitedNodes.contains(sux)) { - return false; - } - } - return true; - } - - private boolean verifyProbabilities() { - if (doesNotAlwaysDeopt(graph)) { - for (AbstractDeoptimizeNode n : graph.getNodes(AbstractDeoptimizeNode.class)) { - if (nodeProbabilities.get(n) > 0.01 && (!(n instanceof DeoptimizeNode) || ((DeoptimizeNode) n).action().doesInvalidateCompilation())) { - throw new AssertionError(String.format("%s with probability %f in graph %s", n, nodeProbabilities.get(n), graph)); - } - } - } - return true; - } - - private static boolean doesNotAlwaysDeopt(StructuredGraph graph) { - return graph.getNodes(ReturnNode.class).isNotEmpty(); - } - private void computeLoopFactors() { for (LoopInfo info : loopInfos) { double frequency = info.loopFrequency(nodeProbabilities); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -59,7 +59,7 @@ /** * This constructor creates a {@link SchedulingError} with a message assembled via * {@link String#format(String, Object...)}. - * + * * @param format a {@linkplain Formatter format} string * @param args parameters to {@link String#format(String, Object...)} */ @@ -164,9 +164,9 @@ /** * gather all kill locations by iterating trough the nodes assigned to a block. - * + * * assumptions: {@link MemoryCheckpoint MemoryCheckPoints} are {@link FixedNode FixedNodes}. - * + * * @param block block to analyze * @param excludeNode if null, compute normal set of kill locations. if != null, don't add kills * until we reach excludeNode. @@ -293,19 +293,20 @@ private void printSchedule(String desc) { if (Debug.isLogEnabled()) { - Debug.printf("=== %s / %s / %s (%s) ===\n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, memsched, desc); + Formatter buf = new Formatter(); + buf.format("=== %s / %s / %s (%s) ===%n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, memsched, desc); for (Block b : getCFG().getBlocks()) { - Debug.printf("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth()); - Debug.printf("dom: %s. ", b.getDominator()); - Debug.printf("post-dom: %s. ", b.getPostdominator()); - Debug.printf("preds: %s. ", b.getPredecessors()); - Debug.printf("succs: %s ====\n", b.getSuccessors()); + buf.format("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth()); + buf.format("dom: %s. ", b.getDominator()); + buf.format("post-dom: %s. ", b.getPostdominator()); + buf.format("preds: %s. ", b.getPredecessors()); + buf.format("succs: %s ====%n", b.getSuccessors()); BlockMap killSets = blockToKillSet; if (killSets != null) { - Debug.printf("X block kills: \n"); + buf.format("X block kills: %n"); if (killSets.get(b) != null) { for (LocationIdentity locId : killSets.get(b)) { - Debug.printf("X %s killed by %s\n", locId, "dunno anymore"); + buf.format("X %s killed by %s%n", locId, "dunno anymore"); } } } @@ -320,28 +321,30 @@ } } } - Debug.printf("\n\n"); + buf.format("%n"); + Debug.log("%s", buf); } } private static void printNode(Node n) { - Debug.printf("%s", n); + Formatter buf = new Formatter(); + buf.format("%s", n); if (n instanceof MemoryCheckpoint.Single) { - Debug.printf(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity()); + buf.format(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity()); } else if (n instanceof MemoryCheckpoint.Multi) { - Debug.printf(" // kills "); + buf.format(" // kills "); for (LocationIdentity locid : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) { - Debug.printf("%s, ", locid); + buf.format("%s, ", locid); } } else if (n instanceof FloatingReadNode) { FloatingReadNode frn = (FloatingReadNode) n; - Debug.printf(" // from %s", frn.location().getLocationIdentity()); - Debug.printf(", lastAccess: %s", frn.getLastLocationAccess()); - Debug.printf(", object: %s", frn.object()); + buf.format(" // from %s", frn.location().getLocationIdentity()); + buf.format(", lastAccess: %s", frn.getLastLocationAccess()); + buf.format(", object: %s", frn.object()); } else if (n instanceof GuardNode) { - Debug.printf(", guard: %s", ((GuardNode) n).getGuard()); + buf.format(", guard: %s", ((GuardNode) n).getGuard()); } - Debug.printf("\n"); + Debug.log("%s", buf); } public ControlFlowGraph getCFG() { @@ -410,7 +413,7 @@ if (scheduleRead) { FloatingReadNode read = (FloatingReadNode) node; block = optimalBlock(read, strategy); - Debug.printf("schedule for %s: %s\n", read, block); + Debug.log("schedule for %s: %s", read, block); assert earliestBlock.dominates(block) : String.format("%s (%s) cannot be scheduled before earliest schedule (%s). location: %s", read, block, earliestBlock, read.getLocationIdentity()); } else { @@ -457,9 +460,9 @@ * this method tries to find the "optimal" schedule for a read, by pushing it down towards its * latest schedule starting by the earliest schedule. By doing this, it takes care of memory * dependencies using kill sets. - * + * * In terms of domination relation, it looks like this: - * + * *
          *    U      upperbound block, defined by last access location of the floating read
          *    ▲
    @@ -469,9 +472,9 @@
          *    ▲
          *    L      latest block
          * 
    - * + * * i.e. upperbound `dom` earliest `dom` optimal `dom` latest. - * + * */ private Block optimalBlock(FloatingReadNode n, SchedulingStrategy strategy) { assert memsched == MemoryScheduling.OPTIMAL; @@ -486,14 +489,14 @@ Block latestBlock = latestBlock(n, strategy); assert latestBlock != null && earliestBlock.dominates(latestBlock) : "earliest (" + earliestBlock + ") should dominate latest block (" + latestBlock + ")"; - Debug.printf("processing %s (accessing %s): latest %s, earliest %s, upper bound %s (%s)\n", n, locid, latestBlock, earliestBlock, upperBoundBlock, n.getLastLocationAccess()); + Debug.log("processing %s (accessing %s): latest %s, earliest %s, upper bound %s (%s)", n, locid, latestBlock, earliestBlock, upperBoundBlock, n.getLastLocationAccess()); if (earliestBlock == latestBlock) { // read is fixed to this block, nothing to schedule return latestBlock; } Deque path = computePathInDominatorTree(earliestBlock, latestBlock); - Debug.printf("|path| is %d: %s\n", path.size(), path); + Debug.log("|path| is %d: %s", path.size(), path); // follow path, start at earliest schedule while (path.size() > 0) { @@ -504,7 +507,7 @@ assert dominatedBlock.getBeginNode() instanceof MergeNode; HashSet region = computeRegion(currentBlock, dominatedBlock); - Debug.printf("> merge. %s: region for %s -> %s: %s\n", n, currentBlock, dominatedBlock, region); + Debug.log("> merge. %s: region for %s -> %s: %s", n, currentBlock, dominatedBlock, region); NewMemoryScheduleClosure closure = null; if (currentBlock == upperBoundBlock) { @@ -540,7 +543,7 @@ /** * compute path in dominator tree from earliest schedule to latest schedule. - * + * * @return the order of the stack is such as the first element is the earliest schedule. */ private static Deque computePathInDominatorTree(Block earliestBlock, Block latestBlock) { @@ -582,7 +585,7 @@ /** * Calculates the last block that the given node could be scheduled in, i.e., the common * dominator of all usages. To do so all usages are also assigned to blocks. - * + * * @param strategy */ private Block latestBlock(ScheduledNode node, SchedulingStrategy strategy) { @@ -643,7 +646,7 @@ * implies that the inputs' blocks have a total ordering via their dominance relation. So in * order to find the earliest block placement for this node we need to find the input block * that is dominated by all other input blocks. - * + * * While iterating over the inputs a set of dominator blocks of the current earliest * placement is maintained. When the block of an input is not within this set, it becomes * the current earliest placement and the list of dominator blocks is updated. @@ -680,7 +683,7 @@ * Schedules a node out of loop based on its earliest schedule. Note that this movement is only * valid if it's done for every other node in the schedule, otherwise this movement is * not valid. - * + * * @param n Node to schedule * @param latestBlock latest possible schedule for {@code n} * @param earliest earliest possible schedule for {@code n} @@ -705,7 +708,7 @@ /** * Passes all blocks that a specific usage of a node is in to a given closure. This is more * complex than just taking the usage's block because of of PhiNodes and FrameStates. - * + * * @param node the node that needs to be scheduled * @param usage the usage whose blocks need to be considered * @param closure the closure that will be called for each block @@ -966,14 +969,18 @@ return; } - FrameState state = null; + FrameState stateAfter = null; + if (i instanceof StateSplit) { + stateAfter = ((StateSplit) i).stateAfter(); + } + for (Node input : i.inputs()) { if (input instanceof FrameState) { - assert state == null; - state = (FrameState) input; + if (input != stateAfter) { + addUnscheduledToLatestSorting(b, (FrameState) input, sortedInstructions, visited, reads, beforeLastLocation); + } } else { addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation); - } } @@ -991,7 +998,7 @@ addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited, reads, beforeLastLocation); visited.mark(i); - addUnscheduledToLatestSorting(b, state, sortedInstructions, visited, reads, beforeLastLocation); + addUnscheduledToLatestSorting(b, stateAfter, sortedInstructions, visited, reads, beforeLastLocation); // Now predecessors and inputs are scheduled => we can add this node. if (!sortedInstructions.contains(i)) { @@ -1038,7 +1045,7 @@ } if (instruction instanceof AbstractBeginNode) { - ArrayList proxies = (instruction instanceof LoopExitNode) ? new ArrayList() : null; + ArrayList proxies = (instruction instanceof LoopExitNode) ? new ArrayList<>() : null; for (ScheduledNode inBlock : blockToNodesMap.get(b)) { if (!visited.isMarked(inBlock)) { if (inBlock instanceof ProxyNode) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Sun Mar 30 16:08:33 2014 +0200 @@ -60,7 +60,13 @@ if (input instanceof FrameState && node instanceof StateSplit && input == ((StateSplit) node).stateAfter()) { // nothing to do - after frame states are known, allowed cycles } else { - assert false : "unexpected cycle detected at input " + node + " -> " + input; + /* + * TODO assertion does not hold for Substrate VM (in general for all + * notDataflow inputs) + * + * assert false : "unexpected cycle detected at input " + node + " -> " + * + input; + */ } } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyDebugUsage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyDebugUsage.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.phases.verify; + +import static com.oracle.graal.api.meta.MetaUtil.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; + +/** + * Verifies that no argument to one of the {@link Debug#log(String)} methods is the result of + * {@link StringBuilder#toString()} or {@link StringBuffer#toString()}. Instead, one of the + * multi-parameter {@code log()} methods should be used. The goal is to minimize/prevent allocation + * at logging call sites. + */ +public class VerifyDebugUsage extends VerifyPhase { + + @Override + protected boolean verify(StructuredGraph graph, PhaseContext context) { + for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.class)) { + ResolvedJavaMethod callee = t.targetMethod(); + ResolvedJavaType debugType = context.getMetaAccess().lookupJavaType(Debug.class); + if (callee.getDeclaringClass().equals(debugType)) { + if (callee.getName().equals("log")) { + int argIdx = 1; + for (ValueNode arg : t.arguments()) { + if (arg instanceof Invoke) { + Invoke invoke = (Invoke) arg; + CallTargetNode callTarget = invoke.callTarget(); + if (callTarget instanceof MethodCallTargetNode) { + ResolvedJavaMethod m = ((MethodCallTargetNode) callTarget).targetMethod(); + if (m.getName().equals("toString")) { + String holder = m.getDeclaringClass().getName(); + if (holder.equals("Ljava/lang/StringBuilder;") || holder.equals("Ljava/lang/StringBuffer;")) { + StackTraceElement e = graph.method().asStackTraceElement(invoke.bci()); + throw new VerificationError(String.format("%s: parameter %d of call to %s appears to be a String concatenation expression.%n" + + " Use one of the multi-parameter Debug.log() methods or Debug.logv() instead.", e, argIdx, format("%H.%n(%p)", callee))); + } + } + } + } + argIdx++; + } + } + } + } + return true; + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Sun Mar 30 16:08:33 2014 +0200 @@ -50,7 +50,7 @@ protected TargetDescription target; protected LIR lir; - protected LIRGenerator lirGenerator; + protected NodeLIRGenerator nodeLirGenerator; protected ControlFlowGraph cfg; protected SchedulePhase schedule; @@ -73,7 +73,7 @@ public void printCFG(String label, BciBlockMapping blockMap) { begin("cfg"); out.print("name \"").print(label).println('"'); - for (BciBlockMapping.Block block : blockMap.blocks) { + for (BciBlockMapping.BciBlock block : blockMap.blocks) { begin("block"); printBlock(block); end("block"); @@ -81,7 +81,7 @@ end("cfg"); } - private void printBlock(BciBlockMapping.Block block) { + private void printBlock(BciBlockMapping.BciBlock block) { out.print("name \"B").print(block.startBci).println('"'); out.print("from_bci ").println(block.startBci); out.print("to_bci ").println(block.endBci); @@ -89,7 +89,7 @@ out.println("predecessors "); out.print("successors "); - for (BciBlockMapping.Block succ : block.successors) { + for (BciBlockMapping.BciBlock succ : block.getSuccessors()) { if (!succ.isExceptionEntry) { out.print("\"B").print(succ.startBci).print("\" "); } @@ -97,7 +97,7 @@ out.println(); out.print("xhandlers"); - for (BciBlockMapping.Block succ : block.successors) { + for (BciBlockMapping.BciBlock succ : block.getSuccessors()) { if (succ.isExceptionEntry) { out.print("\"B").print(succ.startBci).print("\" "); } @@ -129,10 +129,11 @@ * @param label A label describing the compilation phase that produced the control flow graph. * @param blocks The list of blocks to be printed. */ - public void printCFG(String label, List blocks, boolean printNodes) { + public void printCFG(String label, List> blocks, boolean printNodes) { if (lir == null) { latestScheduling = new NodeMap<>(cfg.getNodeToBlock()); - for (Block block : blocks) { + for (AbstractBlock abstractBlock : blocks) { + Block block = (Block) abstractBlock; Node cur = block.getBeginNode(); while (true) { assert inFixedSchedule(cur) && latestScheduling.get(cur) == block; @@ -146,17 +147,15 @@ } } } - printedNodes = new NodeBitMap(cfg.graph); begin("cfg"); out.print("name \"").print(label).println('"'); - for (Block block : blocks) { + for (AbstractBlock block : blocks) { printBlock(block, printNodes); } end("cfg"); latestScheduling = null; - printedNodes = null; } private void scheduleInputs(Node node, Block nodeBlock) { @@ -187,20 +186,21 @@ } } - private void printBlock(Block block, boolean printNodes) { + private void printBlock(AbstractBlock block, boolean printNodes) { printBlockProlog(block); if (printNodes) { - printNodes(block); + assert block instanceof Block; + printNodes((Block) block); } printBlockEpilog(block); } - private void printBlockEpilog(Block block) { + private void printBlockEpilog(AbstractBlock block) { printLIR(block); end("block"); } - private void printBlockProlog(Block block) { + private void printBlockProlog(AbstractBlock block) { begin("block"); out.print("name \"").print(blockToString(block)).println('"'); @@ -208,13 +208,13 @@ out.println("to_bci -1"); out.print("predecessors "); - for (Block pred : block.getPredecessors()) { + for (AbstractBlock pred : block.getPredecessors()) { out.print("\"").print(blockToString(pred)).print("\" "); } out.println(); out.print("successors "); - for (Block succ : block.getSuccessors()) { + for (AbstractBlock succ : block.getSuccessors()) { if (!succ.isExceptionEntry()) { out.print("\"").print(blockToString(succ)).print("\" "); } @@ -222,7 +222,7 @@ out.println(); out.print("xhandlers"); - for (Block succ : block.getSuccessors()) { + for (AbstractBlock succ : block.getSuccessors()) { if (succ.isExceptionEntry()) { out.print("\"").print(blockToString(succ)).print("\" "); } @@ -248,6 +248,7 @@ } private void printNodes(Block block) { + printedNodes = new NodeBitMap(cfg.graph); begin("IR"); out.println("HIR"); out.disableIndentation(); @@ -281,6 +282,7 @@ out.enableIndentation(); end("IR"); + printedNodes = null; } private void printNode(Node node, boolean unscheduled) { @@ -307,8 +309,8 @@ } out.print("tid ").print(nodeToString(node)).println(COLUMN_END); - if (lirGenerator != null) { - Value operand = lirGenerator.nodeOperands.get(node); + if (nodeLirGenerator != null) { + Value operand = nodeLirGenerator.getNodeOperands().get(node); if (operand != null) { out.print("result ").print(operand.toString()).println(COLUMN_END); } @@ -412,8 +414,8 @@ private String stateValueToString(ValueNode value) { String result = nodeToString(value); - if (lirGenerator != null && lirGenerator.nodeOperands != null && value != null) { - Value operand = lirGenerator.nodeOperands.get(value); + if (nodeLirGenerator != null && nodeLirGenerator.getNodeOperands() != null && value != null) { + Value operand = nodeLirGenerator.getNodeOperands().get(value); if (operand != null) { result += ": " + operand; } @@ -426,11 +428,11 @@ * * @param block the block to print */ - private void printLIR(Block block) { + private void printLIR(AbstractBlock block) { if (lir == null) { return; } - List lirInstructions = lir.lir(block); + List lirInstructions = lir.getLIRforBlock(block); if (lirInstructions == null) { return; } @@ -477,10 +479,10 @@ prefix = "B"; } else if (node instanceof ValueNode) { ValueNode value = (ValueNode) node; - if (value.kind() == Kind.Illegal) { + if (value.getKind() == Kind.Illegal) { prefix = "v"; } else { - prefix = String.valueOf(value.kind().getTypeChar()); + prefix = String.valueOf(value.getKind().getTypeChar()); } } else { prefix = "?"; @@ -488,13 +490,13 @@ return prefix + node.toString(Verbosity.Id); } - private String blockToString(Block block) { - if (lir == null && schedule == null) { + private String blockToString(AbstractBlock block) { + if (lir == null && schedule == null && block instanceof Block) { // During all the front-end phases, the block schedule is built only for the debug // output. // Therefore, the block numbers would be different for every CFG printed -> use the id // of the first instruction. - return "B" + block.getBeginNode().toString(Verbosity.Id); + return "B" + ((Block) block).getBeginNode().toString(Verbosity.Id); } else { // LIR instructions contain references to blocks and these blocks are printed as the // blockID -> use the blockID. diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Sun Mar 30 16:08:33 2014 +0200 @@ -137,12 +137,12 @@ } else { cfgPrinter.lir = Debug.contextLookup(LIR.class); } - cfgPrinter.lirGenerator = Debug.contextLookup(LIRGenerator.class); - if (cfgPrinter.lirGenerator != null) { - cfgPrinter.target = cfgPrinter.lirGenerator.target(); + cfgPrinter.nodeLirGenerator = Debug.contextLookup(NodeLIRGenerator.class); + if (cfgPrinter.nodeLirGenerator != null) { + cfgPrinter.target = cfgPrinter.nodeLirGenerator.getLIRGeneratorTool().target(); } - if (cfgPrinter.lir != null) { - cfgPrinter.cfg = cfgPrinter.lir.getControlFlowGraph(); + if (cfgPrinter.lir != null && cfgPrinter.lir.getControlFlowGraph() instanceof ControlFlowGraph) { + cfgPrinter.cfg = (ControlFlowGraph) cfgPrinter.lir.getControlFlowGraph(); } CodeCacheProvider codeCache = Debug.contextLookup(CodeCacheProvider.class); @@ -160,7 +160,7 @@ } else if (object instanceof LIR) { // No need to print the HIR nodes again if this is not the first // time dumping the same LIR since the HIR will not have changed. - boolean printNodes = previousObject != object; + boolean printNodes = previousObject != object && cfgPrinter.cfg != null; cfgPrinter.printCFG(message, cfgPrinter.lir.codeEmittingOrder(), printNodes); } else if (object instanceof SchedulePhase) { @@ -185,7 +185,7 @@ cfgPrinter.target = null; cfgPrinter.lir = null; - cfgPrinter.lirGenerator = null; + cfgPrinter.nodeLirGenerator = null; cfgPrinter.cfg = null; cfgPrinter.flush(); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Sun Mar 30 16:08:33 2014 +0200 @@ -115,7 +115,7 @@ if (PrintBinaryGraphs.getValue()) { printer = new BinaryGraphPrinter(FileChannel.open(file.toPath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)); } else { - printer = new IdealGraphPrinter(new FileOutputStream(file)); + printer = new IdealGraphPrinter(new FileOutputStream(file), true); } TTY.println("Dumping IGV graphs to %s", file.getName()); } catch (IOException e) { @@ -132,7 +132,7 @@ if (PrintBinaryGraphs.getValue()) { printer = new BinaryGraphPrinter(SocketChannel.open(new InetSocketAddress(host, port))); } else { - IdealGraphPrinter xmlPrinter = new IdealGraphPrinter(new Socket(host, port).getOutputStream()); + IdealGraphPrinter xmlPrinter = new IdealGraphPrinter(new Socket(host, port).getOutputStream(), true); printer = xmlPrinter; } TTY.println("Connected to the IGV on %s:%d", host, port); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java Sun Mar 30 16:08:33 2014 +0200 @@ -293,9 +293,8 @@ } void warning(int offset, String message) { - // CheckStyle: stop system..print check - System.err.println("Warning: " + errorMessage(offset, message)); - // CheckStyle: resume system..print check + PrintStream err = System.err; + err.println("Warning: " + errorMessage(offset, message)); } String errorMessage(int offset, String message) { @@ -323,10 +322,9 @@ int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1; String l = input.substring(lineStart, lineStart + 10); - // CheckStyle: stop system..print check - System.out.println("YYY" + input.substring(index, index + 10) + "..."); - System.out.println("XXX" + l + "..."); - // CheckStyle: resume system..print check + PrintStream out = System.out; + out.println("YYY" + input.substring(index, index + 10) + "..."); + out.println("XXX" + l + "..."); int pos = input.indexOf(HexCodeFile.NEW_LINE, 0); int line = 1; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Sun Mar 30 16:08:33 2014 +0200 @@ -42,12 +42,18 @@ */ public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter { + private final boolean tryToSchedule; + /** * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. + * + * @param tryToSchedule If false, no scheduling is done, which avoids exceptions for + * non-schedulable graphs. */ - public IdealGraphPrinter(OutputStream stream) { + public IdealGraphPrinter(OutputStream stream, boolean tryToSchedule) { super(stream); this.begin(); + this.tryToSchedule = tryToSchedule; } /** @@ -80,7 +86,7 @@ beginGraph(title); Set noBlockNodes = new HashSet<>(); SchedulePhase schedule = predefinedSchedule; - if (schedule == null) { + if (schedule == null && tryToSchedule) { try { schedule = new SchedulePhase(); schedule.apply((StructuredGraph) graph); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -51,7 +51,7 @@ throw GraalInternalError.shouldNotReachHere(); } - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitFloatConvert(op, gen.operand(value))); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitFloatConvert(op, gen.operand(value))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java --- a/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements.hsail/src/com/oracle/graal/replacements/hsail/HSAILMathIntrinsicsNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,8 +33,7 @@ import com.oracle.graal.nodes.calc.FloatingNode; import com.oracle.graal.nodes.ConstantNode; import com.oracle.graal.nodes.ValueNode; -import com.oracle.graal.nodes.spi.ArithmeticLIRGenerator; -import com.oracle.graal.nodes.spi.ArithmeticLIRLowerable; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.StampFactory; /** @@ -77,7 +76,7 @@ * @param op the math operation */ public HSAILMathIntrinsicsNode(ValueNode x, HSAILArithmetic op) { - super(StampFactory.forKind(x.kind())); + super(StampFactory.forKind(x.getKind())); this.param = x; this.operation = op; } @@ -86,24 +85,24 @@ * Generates the LIR instructions for the math operation represented by this node. */ @Override - public void generate(ArithmeticLIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { Value input = gen.operand(getParameter()); Value result; switch (operation()) { case ABS: - result = gen.emitMathAbs(input); + result = gen.getLIRGeneratorTool().emitMathAbs(input); break; case CEIL: - result = ((HSAILLIRGenerator) (gen)).emitMathCeil(input); + result = ((HSAILLIRGenerator) (gen.getLIRGeneratorTool())).emitMathCeil(input); break; case FLOOR: - result = ((HSAILLIRGenerator) (gen)).emitMathFloor(input); + result = ((HSAILLIRGenerator) (gen.getLIRGeneratorTool())).emitMathFloor(input); break; case RINT: - result = ((HSAILLIRGenerator) (gen)).emitMathRint(input); + result = ((HSAILLIRGenerator) (gen.getLIRGeneratorTool())).emitMathRint(input); break; case SQRT: - result = gen.emitMathSqrt(input); + result = gen.getLIRGeneratorTool().emitMathSqrt(input); break; default: @@ -175,4 +174,5 @@ */ @NodeIntrinsic public static native double compute(double value, @ConstantNodeParameter HSAILArithmetic op); + } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,8 +29,12 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.virtual.phases.ea.*; /** * Tests {@link ArraysSubstitutions}. @@ -350,4 +354,90 @@ } } + @Test + public void testConstants() { + test("testConstantsSnippet"); + } + + public static final int[] constantArray1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + public static final int[] constantArray2 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + + public static boolean testConstantsSnippet() { + constantArray2[0] = 10; + try { + return Arrays.equals(constantArray1, constantArray2); + } finally { + constantArray2[0] = 1; + } + } + + @Test + public void testCanonicalLength() { + StructuredGraph graph = parse("testCanonicalLengthSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0); + } + + public static final int[] constantArray3 = new int[]{1, 2, 3}; + + public static boolean testCanonicalLengthSnippet() { + return Arrays.equals(constantArray1, constantArray3); + } + + @Test + public void testCanonicalEqual() { + StructuredGraph graph = parse("testCanonicalEqualSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1); + } + + public static boolean testCanonicalEqualSnippet() { + return Arrays.equals(constantArray1, constantArray1); + } + + @Test + public void testVirtualEqual() { + StructuredGraph graph = parse("testVirtualEqualSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1); + } + + public static boolean testVirtualEqualSnippet() { + int[] array1 = new int[]{1, 2, 3, 4}; + int[] array2 = new int[]{1, 2, 3, 4}; + return Arrays.equals(array1, array2); + } + + @Test + public void testVirtualNotEqual() { + StructuredGraph graph = parse("testVirtualNotEqualSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0); + } + + public static boolean testVirtualNotEqualSnippet(int x) { + int[] array1 = new int[]{1, 2, 100, x}; + int[] array2 = new int[]{1, 2, 3, 4}; + return Arrays.equals(array1, array2); + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java --- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/VerifierAnnotationProcessor.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,12 +30,16 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; -@SupportedSourceVersion(SourceVersion.RELEASE_7) public class VerifierAnnotationProcessor extends AbstractProcessor { private List verifiers; @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (!roundEnv.processingOver()) { for (AbstractVerifier verifier : getVerifiers()) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -175,7 +175,7 @@ for (Node returnSideEffect : returnSideEffects) { if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) { StateSplit split = (StateSplit) returnSideEffect; - if (split.getState() != null) { + if (split.stateAfter() != null) { split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI))); } } @@ -184,7 +184,7 @@ for (Node unwindSideEffect : unwindSideEffects) { if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) { StateSplit split = (StateSplit) unwindSideEffect; - if (split.getState() != null) { + if (split.stateAfter() != null) { split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_EXCEPTION_BCI))); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Sun Mar 30 16:08:33 2014 +0200 @@ -106,7 +106,7 @@ * @param name the name of the invoked method * @param args the arguments to the invocation */ - public InvokeNode createInvoke(Class declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + public InvokeNode createInvoke(Class declaringClass, String name, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { boolean isStatic = invokeKind == InvokeKind.Static; ResolvedJavaMethod method = null; for (Method m : declaringClass.getDeclaredMethods()) { @@ -123,7 +123,7 @@ * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of * arguments. */ - public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { assert Modifier.isStatic(method.getModifiers()) == (invokeKind == InvokeKind.Static); Signature signature = method.getSignature(); JavaType returnType = signature.getReturnType(null); @@ -132,12 +132,12 @@ InvokeNode invoke = append(new InvokeNode(callTarget, bci)); if (frameStateBuilder != null) { - if (invoke.kind() != Kind.Void) { - frameStateBuilder.push(invoke.kind(), invoke); + if (invoke.getKind() != Kind.Void) { + frameStateBuilder.push(invoke.getKind(), invoke); } invoke.setStateAfter(frameStateBuilder.create(0)); - if (invoke.kind() != Kind.Void) { - frameStateBuilder.pop(invoke.kind()); + if (invoke.getKind() != Kind.Void) { + frameStateBuilder.pop(invoke.getKind()); } } return invoke; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -138,7 +138,7 @@ /** * Converts the arguments of an invoke node to object values suitable for use as the arguments * to a reflective invocation of a Java constructor or method. - * + * * @param folding specifies if the invocation is for handling a {@link Fold} annotation * @return the arguments for the reflective invocation or null if an argument of {@code invoke} * that is expected to be constant isn't @@ -326,7 +326,7 @@ public void cleanUpReturnCheckCast(Node newInstance) { if (newInstance.recordsUsages() && newInstance instanceof ValueNode && - (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { + (((ValueNode) newInstance).getKind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { StructuredGraph graph = (StructuredGraph) newInstance.graph(); for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { for (Node checkCastUsage : checkCastNode.usages().snapshot()) { @@ -395,7 +395,7 @@ } graph.removeFixed(pi); } else { - DebugScope.dump(graph, "exception"); + DebugScope.forceDump(graph, "exception"); assert false : sourceLocation(usage) + " has unexpected usage " + usage + " of checkcast " + input + " at " + sourceLocation(input); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sun Mar 30 16:08:33 2014 +0200 @@ -40,6 +40,7 @@ import com.oracle.graal.debug.internal.*; import com.oracle.graal.graph.*; import com.oracle.graal.java.*; +import com.oracle.graal.java.GraphBuilderPhase.Instance; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; @@ -99,7 +100,7 @@ FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal : FrameStateProcessing.CollapseFrameForSingleSideEffect; StructuredGraph newGraph = makeGraph(method, recursiveEntry, recursiveEntry, inliningPolicy(method), frameStateProcessing); - Debug.metric(new MethodDebugValueName("SnippetNodeCount", method)).add(newGraph.getNodeCount()); + Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount()); if (!UseSnippetGraphCache) { return newGraph; } @@ -233,7 +234,9 @@ } else { original = metaAccess.lookupJavaConstructor((Constructor) originalMember); } - Debug.log("substitution: " + MetaUtil.format("%H.%n(%p) %r", original) + " --> " + MetaUtil.format("%H.%n(%p) %r", substitute)); + if (Debug.isLogEnabled()) { + Debug.log("substitution: %s --> %s", MetaUtil.format("%H.%n(%p) %r", original), MetaUtil.format("%H.%n(%p) %r", substitute)); + } registeredMethodSubstitutions.put(original, substitute); return original; @@ -340,7 +343,7 @@ public StructuredGraph makeGraph(final SnippetInliningPolicy policy) { try (Scope s = Debug.scope("BuildSnippetGraph", method)) { - StructuredGraph graph = parseGraph(method, policy); + StructuredGraph graph = parseGraph(method, policy, 0); // Cannot have a finalized version of a graph in the cache graph = graph.copy(); @@ -380,12 +383,14 @@ new DeadCodeEliminationPhase().apply(graph); } - private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) { + private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough + + private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy, int inliningDepth) { StructuredGraph graph = graphCache.get(methodToParse); if (graph == null) { StructuredGraph newGraph = null; try (Scope s = Debug.scope("ParseGraph", methodToParse)) { - newGraph = buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy); + newGraph = buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy, inliningDepth); } catch (Throwable e) { throw Debug.handle(e); } @@ -404,7 +409,7 @@ final StructuredGraph graph = new StructuredGraph(methodToParse); try (Scope s = Debug.scope("buildInitialGraph", graph)) { MetaAccessProvider metaAccess = providers.getMetaAccess(); - new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph); + createGraphBuilder(metaAccess, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph); new WordTypeVerificationPhase(metaAccess, target.wordKind).apply(graph); new WordTypeRewriterPhase(metaAccess, target.wordKind).apply(graph); @@ -417,6 +422,10 @@ return graph; } + protected Instance createGraphBuilder(MetaAccessProvider metaAccess, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + return new GraphBuilderPhase.Instance(metaAccess, graphBuilderConfig, optimisticOpts); + } + protected Object beforeInline(@SuppressWarnings("unused") MethodCallTargetNode callTarget, @SuppressWarnings("unused") StructuredGraph callee) { return null; } @@ -445,7 +454,8 @@ } } - private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) { + private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy, int inliningDepth) { + assert inliningDepth < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; assert isInlinableSnippet(methodToParse) : methodToParse; final StructuredGraph graph = buildInitialGraph(methodToParse); try (Scope s = Debug.scope("buildGraph", graph)) { @@ -477,7 +487,7 @@ " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " + methodToParse.getDeclaringClass().getSourceFileName() + " should fix this."); } - targetGraph = parseGraph(callee, policy); + targetGraph = parseGraph(callee, policy, inliningDepth + 1); } Object beforeInlineData = beforeInline(callTarget, targetGraph); InliningUtil.inline(callTarget.invoke(), targetGraph, true); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Sun Mar 30 16:08:33 2014 +0200 @@ -39,6 +39,7 @@ * snippet specific metrics. */ public class SnippetCounter implements Comparable { + private static final LocationIdentity SNIPPET_COUNTER_LOCATION = new NamedLocationIdentity("SnippetCounter"); /** * A group of related counters. @@ -134,9 +135,7 @@ */ public void inc() { if (group != null) { - // TODO: instead of ANY_LOCATION we should actually - // use the location for the field "value". - DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, LocationIdentity.ANY_LOCATION); + DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, SNIPPET_COUNTER_LOCATION); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,6 +24,8 @@ import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.api.meta.MetaUtil.*; +import static com.oracle.graal.debug.Debug.*; +import static java.util.FormattableFlags.*; import java.io.*; import java.lang.reflect.*; @@ -97,8 +99,8 @@ protected SnippetInfo(ResolvedJavaMethod method) { this.method = method; - instantiationCounter = Debug.metric(new MethodDebugValueName("SnippetInstantiationCount", method)); - instantiationTimer = Debug.timer(new MethodDebugValueName("SnippetInstantiationTime", method)); + instantiationCounter = Debug.metric("SnippetInstantiationCount[%s]", method); + instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", method); assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + MetaUtil.format("%H.%n", method); int count = method.getSignature().getParameterCount(false); constantParameters = new boolean[count]; @@ -176,7 +178,7 @@ * {@link SnippetTemplate#instantiate instantiated} *
*/ - public static class Arguments { + public static class Arguments implements Formattable { protected final SnippetInfo info; protected final CacheKey cacheKey; @@ -243,6 +245,30 @@ result.append(">"); return result.toString(); } + + public void formatTo(Formatter formatter, int flags, int width, int precision) { + if ((flags & ALTERNATE) == 0) { + formatter.format(applyFormattingFlagsAndWidth(toString(), flags, width)); + } else { + StringBuilder sb = new StringBuilder(); + sb.append(info.method.getName()).append('('); + String sep = ""; + for (int i = 0; i < info.getParameterCount(); i++) { + if (info.isConstantParameter(i)) { + sb.append(sep); + if (info.names[i] != null) { + sb.append(info.names[i]); + } else { + sb.append(i); + } + sb.append('=').append(values[i]); + sep = ", "; + } + } + sb.append(")"); + formatter.format(applyFormattingFlagsAndWidth(sb.toString(), flags & ~ALTERNATE, width)); + } + } } /** @@ -440,38 +466,13 @@ return false; } - private static String debugValueName(String category, Arguments args) { - if (Debug.isEnabled()) { - StringBuilder result = new StringBuilder(category).append('['); - SnippetInfo info = args.info; - result.append(info.method.getName()).append('('); - String sep = ""; - for (int i = 0; i < info.getParameterCount(); i++) { - if (info.isConstantParameter(i)) { - result.append(sep); - if (info.names[i] != null) { - result.append(info.names[i]); - } else { - result.append(i); - } - result.append('=').append(args.values[i]); - sep = ", "; - } - } - result.append(")]"); - return result.toString(); - - } - return null; - } - /** * Creates a snippet template. */ protected SnippetTemplate(final Providers providers, Arguments args) { StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method); - instantiationTimer = Debug.timer(debugValueName("SnippetTemplateInstantiationTime", args)); - instantiationCounter = Debug.metric(debugValueName("SnippetTemplateInstantiationCount", args)); + instantiationTimer = Debug.timer("SnippetTemplateInstantiationTime[%#s]", args); + instantiationCounter = Debug.metric("SnippetTemplateInstantiationCount[%#s]", args); ResolvedJavaMethod method = snippetGraph.method(); Signature signature = method.getSignature(); @@ -665,7 +666,7 @@ } } - Debug.metric(debugValueName("SnippetTemplateNodeCount", args)).add(nodes.size()); + Debug.metric("SnippetTemplateNodeCount[%#s]", args).add(nodes.size()); args.info.notifyNewTemplate(); Debug.dump(snippet, "SnippetTemplate final state"); } @@ -727,8 +728,8 @@ private final ArrayList sideEffectNodes; /** - * Nodes that inherit the {@link DeoptimizingNode#getDeoptimizationState()} from the replacee - * during instantiation. + * Nodes that inherit a deoptimization {@link FrameState} from the replacee during + * instantiation. */ private final ArrayList deoptNodes; @@ -777,7 +778,7 @@ if (argument instanceof ValueNode) { replacements.put((ParameterNode) parameter, (ValueNode) argument); } else { - Kind kind = ((ParameterNode) parameter).kind(); + Kind kind = ((ParameterNode) parameter).getKind(); assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + args.info.names[i]; Constant constant = forBoxed(argument, kind); replacements.put((ParameterNode) parameter, ConstantNode.forConstant(constant, metaAccess, replaceeGraph)); @@ -804,7 +805,7 @@ if (value instanceof ValueNode) { replacements.put(param, (ValueNode) value); } else { - Constant constant = forBoxed(value, param.kind()); + Constant constant = forBoxed(value, param.getKind()); ConstantNode element = ConstantNode.forConstant(constant, metaAccess, replaceeGraph); replacements.put(param, element); } @@ -1023,11 +1024,50 @@ if (replacee instanceof DeoptimizingNode) { DeoptimizingNode replaceeDeopt = (DeoptimizingNode) replacee; - FrameState state = replaceeDeopt.getDeoptimizationState(); + + FrameState stateBefore = null; + FrameState stateDuring = null; + FrameState stateAfter = null; + if (replaceeDeopt.canDeoptimize()) { + if (replaceeDeopt instanceof DeoptimizingNode.DeoptBefore) { + stateBefore = ((DeoptimizingNode.DeoptBefore) replaceeDeopt).stateBefore(); + } + if (replaceeDeopt instanceof DeoptimizingNode.DeoptDuring) { + stateDuring = ((DeoptimizingNode.DeoptDuring) replaceeDeopt).stateDuring(); + } + if (replaceeDeopt instanceof DeoptimizingNode.DeoptAfter) { + stateAfter = ((DeoptimizingNode.DeoptAfter) replaceeDeopt).stateAfter(); + } + } + for (DeoptimizingNode deoptNode : deoptNodes) { DeoptimizingNode deoptDup = (DeoptimizingNode) duplicates.get(deoptNode); - assert replaceeDeopt.canDeoptimize() || !deoptDup.canDeoptimize(); - deoptDup.setDeoptimizationState(state); + if (deoptDup.canDeoptimize()) { + if (deoptDup instanceof DeoptimizingNode.DeoptBefore) { + ((DeoptimizingNode.DeoptBefore) deoptDup).setStateBefore(stateBefore); + } + if (deoptDup instanceof DeoptimizingNode.DeoptDuring) { + DeoptimizingNode.DeoptDuring deoptDupDuring = (DeoptimizingNode.DeoptDuring) deoptDup; + if (stateDuring != null) { + deoptDupDuring.setStateDuring(stateDuring); + } else if (stateAfter != null) { + deoptDupDuring.computeStateDuring(stateAfter); + } else if (stateBefore != null) { + assert !deoptDupDuring.hasSideEffect() : "can't use stateBefore as stateDuring for state split " + deoptDupDuring; + deoptDupDuring.setStateDuring(stateBefore); + } + } + if (deoptDup instanceof DeoptimizingNode.DeoptAfter) { + DeoptimizingNode.DeoptAfter deoptDupAfter = (DeoptimizingNode.DeoptAfter) deoptDup; + if (stateAfter != null) { + deoptDupAfter.setStateAfter(stateAfter); + } else { + assert !deoptDupAfter.hasSideEffect() : "can't use stateBefore as stateAfter for state split " + deoptDupAfter; + deoptDupAfter.setStateAfter(stateBefore); + } + + } + } } } @@ -1171,10 +1211,10 @@ buf.append(" ").append(name); } else if (value instanceof ParameterNode) { ParameterNode param = (ParameterNode) value; - buf.append(param.kind().getJavaName()).append(' ').append(name); + buf.append(param.getKind().getJavaName()).append(' ').append(name); } else { ParameterNode[] params = (ParameterNode[]) value; - String kind = params.length == 0 ? "?" : params[0].kind().getJavaName(); + String kind = params.length == 0 ? "?" : params[0].getKind().getJavaName(); buf.append(kind).append('[').append(params.length).append("] ").append(name); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,6 +30,8 @@ import com.oracle.graal.graph.*; import com.oracle.graal.replacements.nodes.*; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * Substitutions for {@link java.lang.String} methods. */ @@ -51,6 +53,7 @@ } @MethodSubstitution(isStatic = false) + @SuppressFBWarnings(value = "ES_COMPARING_PARAMETER_STRING_WITH_EQ", justification = "reference equality on the receiver is what we want") public static boolean equals(final String thisString, Object obj) { if (thisString == obj) { return true; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.replacements.nodes; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; @@ -31,12 +29,14 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; /** * Compares two arrays with the same length. */ -public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable { +public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable { /** {@link Kind} of the arrays to compare. */ private final Kind kind; @@ -65,42 +65,45 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (!array1.isConstant() || !array2.isConstant()) { - return this; + if (usages().isEmpty()) { + return null; } + if (GraphUtil.unproxify(array1) == GraphUtil.unproxify(array2)) { + return ConstantNode.forBoolean(true, graph()); + } + return this; + } - Object a1 = array1.asConstant().asObject(); - Object a2 = array2.asConstant().asObject(); - boolean x; - switch (kind) { - case Boolean: - x = Arrays.equals((boolean[]) a1, (boolean[]) a2); - break; - case Byte: - x = Arrays.equals((byte[]) a1, (byte[]) a2); - break; - case Char: - x = Arrays.equals((char[]) a1, (char[]) a2); - break; - case Short: - x = Arrays.equals((short[]) a1, (short[]) a2); - break; - case Int: - x = Arrays.equals((int[]) a1, (int[]) a2); - break; - case Long: - x = Arrays.equals((long[]) a1, (long[]) a2); - break; - case Float: - x = Arrays.equals((float[]) a1, (float[]) a2); - break; - case Double: - x = Arrays.equals((double[]) a1, (double[]) a2); - break; - default: - throw GraalInternalError.shouldNotReachHere("unknown kind " + kind); + public void virtualize(VirtualizerTool tool) { + State state1 = tool.getObjectState(array1); + if (state1 != null) { + State state2 = tool.getObjectState(array2); + if (state2 != null) { + if (state1.getVirtualObject() == state2.getVirtualObject()) { + // the same virtual objects will always have the same contents + tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); + } else if (state1.getVirtualObject().entryCount() == state2.getVirtualObject().entryCount()) { + int entryCount = state1.getVirtualObject().entryCount(); + boolean allEqual = true; + for (int i = 0; i < entryCount; i++) { + ValueNode entry1 = state1.getEntry(i); + ValueNode entry2 = state2.getEntry(i); + if (entry1 != entry2) { + // the contents might be different + allEqual = false; + } + if (entry1.stamp().alwaysDistinct(entry2.stamp())) { + // the contents are different + tool.replaceWithValue(ConstantNode.forBoolean(false, graph())); + return; + } + } + if (allEqual) { + tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); + } + } + } } - return ConstantNode.forBoolean(x, graph()); } @NodeIntrinsic @@ -128,7 +131,7 @@ public static native boolean equals(double[] array1, double[] array2, int length); @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGenerator gen) { Variable result = gen.newVariable(Kind.Int); gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length)); gen.setResult(this, result); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -65,7 +65,7 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGenerator gen) { Variable result = gen.newVariable(Kind.Int); gen.emitBitCount(result, gen.operand(value)); gen.setResult(this, result); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -72,7 +72,7 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGenerator gen) { Variable result = gen.newVariable(Kind.Int); gen.emitBitScanForward(result, gen.operand(value)); gen.setResult(this, result); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -79,9 +79,9 @@ } @Override - public void generate(LIRGenerator gen) { + public void generate(NodeLIRGenerator gen) { Variable result = gen.newVariable(Kind.Int); - gen.emitBitScanReverse(result, gen.operand(value)); + gen.getLIRGeneratorTool().emitBitScanReverse(result, gen.operand(value)); gen.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -58,8 +58,8 @@ @Override public void lower(LoweringTool tool) { - IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, value.kind(), displacement, offset, graph(), 1); - WriteNode write = graph().add(new WriteNode(object, value, location, BarrierType.NONE, value.kind() == Kind.Object)); + IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, value.getKind(), displacement, offset, graph(), 1); + WriteNode write = graph().add(new WriteNode(object, value, location, BarrierType.NONE, value.getKind() == Kind.Object)); graph().replaceFixedWithFixed(this, write); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -46,8 +46,8 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), null)); + public void generate(NodeLIRGeneratorTool gen) { + gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, gen.operand(address), null)); } @SuppressWarnings("unchecked") diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -48,9 +48,9 @@ } @Override - public void generate(LIRGeneratorTool gen) { + public void generate(NodeLIRGeneratorTool gen) { Value v = gen.operand(value); - gen.emitStore(kind, gen.operand(address), v, null); + gen.getLIRGeneratorTool().emitStore(kind, gen.operand(address), v, null); } /* diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -159,7 +159,7 @@ InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci)); if (stateAfter() != null) { invoke.setStateAfter(stateAfter().duplicate()); - if (kind() != Kind.Void) { + if (getKind() != Kind.Void) { invoke.stateAfter().replaceFirstInput(this, invoke); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -55,30 +55,30 @@ } @Override - public void generate(ArithmeticLIRGenerator gen) { + public void generate(NodeLIRGeneratorTool gen) { Value input = gen.operand(x()); Value result; switch (operation()) { case ABS: - result = gen.emitMathAbs(input); + result = gen.getLIRGeneratorTool().emitMathAbs(input); break; case SQRT: - result = gen.emitMathSqrt(input); + result = gen.getLIRGeneratorTool().emitMathSqrt(input); break; case LOG: - result = gen.emitMathLog(input, false); + result = gen.getLIRGeneratorTool().emitMathLog(input, false); break; case LOG10: - result = gen.emitMathLog(input, true); + result = gen.getLIRGeneratorTool().emitMathLog(input, true); break; case SIN: - result = gen.emitMathSin(input); + result = gen.getLIRGeneratorTool().emitMathSin(input); break; case COS: - result = gen.emitMathCos(input); + result = gen.getLIRGeneratorTool().emitMathCos(input); break; case TAN: - result = gen.emitMathTan(input); + result = gen.getLIRGeneratorTool().emitMathTan(input); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -88,7 +88,7 @@ public Constant evalConst(Constant... inputs) { assert inputs.length == 1; - return Constant.forDouble(compute(inputs[0].asDouble(), operation())); + return Constant.forDouble(doCompute(inputs[0].asDouble(), operation())); } @Override @@ -101,6 +101,10 @@ @NodeIntrinsic public static double compute(double value, @ConstantNodeParameter Operation op) { + return doCompute(value, op); + } + + private static double doCompute(double value, Operation op) throws GraalInternalError { switch (op) { case ABS: return Math.abs(value); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,17 +24,16 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; /** * Access the value of a specific register. */ @NodeInfo(nameTemplate = "ReadRegister %{p#register}") -public final class ReadRegisterNode extends FixedWithNextNode implements LIRGenLowerable { +public final class ReadRegisterNode extends FixedWithNextNode implements LIRLowerable { /** * The fixed register to access. @@ -75,13 +74,13 @@ } @Override - public void generate(LIRGenerator generator) { - Value result = register.asValue(kind()); + public void generate(NodeLIRGeneratorTool generator) { + Value result = register.asValue(getKind()); if (incoming) { - generator.emitIncomingValues(new Value[]{result}); + generator.getLIRGeneratorTool().emitIncomingValues(new Value[]{result}); } if (!directUse) { - result = generator.emitMove(result); + result = generator.getLIRGeneratorTool().emitMove(result); } generator.setResult(this, result); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -37,8 +37,8 @@ @Input private ValueNode value; public ReverseBytesNode(ValueNode value) { - super(StampFactory.forKind(value.kind())); - assert kind().isNumericInteger(); + super(StampFactory.forKind(value.getKind())); + assert getKind().isNumericInteger(); this.value = value; } @@ -46,9 +46,9 @@ public Node canonical(CanonicalizerTool tool) { if (value.isConstant()) { long v = value.asConstant().asLong(); - if (kind().getStackKind() == Kind.Int) { + if (getKind().getStackKind() == Kind.Int) { return ConstantNode.forInt(Integer.reverseBytes((int) v), graph()); - } else if (kind() == Kind.Long) { + } else if (getKind() == Kind.Long) { return ConstantNode.forLong(Long.reverseBytes(v), graph()); } } @@ -66,9 +66,9 @@ } @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(value.kind()); - gen.emitByteSwap(result, gen.operand(value)); + public void generate(NodeLIRGenerator gen) { + Variable result = gen.newVariable(value.getKind()); + gen.getLIRGenerator().emitByteSwap(result, gen.operand(value)); gen.setResult(this, result); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -52,9 +52,9 @@ } @Override - public void generate(LIRGeneratorTool generator) { + public void generate(NodeLIRGeneratorTool generator) { Value val = generator.operand(value); - generator.emitMove(register.asValue(val.getKind()), val); + generator.getLIRGeneratorTool().emitMove(register.asValue(val.getKind()), val); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java --- a/graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java Sun Mar 30 16:08:33 2014 +0200 @@ -34,12 +34,16 @@ import com.oracle.graal.api.runtime.*; -@SupportedSourceVersion(SourceVersion.RELEASE_7) @SupportedAnnotationTypes("com.oracle.graal.api.runtime.ServiceProvider") public class ServiceProviderProcessor extends AbstractProcessor { private final Set processed = new HashSet<>(); + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + private boolean verifyAnnotation(TypeMirror serviceInterface, TypeElement serviceProvider) { if (!processingEnv.getTypeUtils().isSubtype(serviceProvider.asType(), serviceInterface)) { String msg = String.format("Service provider class %s doesn't implement service interface %s", serviceProvider.getSimpleName(), serviceInterface); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java --- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -48,6 +48,15 @@ found = m; } } + if (found == null) { + /* Now look for non-public methods (but this does not look in superclasses). */ + for (Method m : clazz.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + Assert.assertNull(found); + found = m; + } + } + } if (found != null) { return found; } else { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -62,7 +62,7 @@ @Child private AbstractTestNode child; public CatchControlFlowExceptionTestNode(AbstractTestNode child) { - this.child = adoptChild(child); + this.child = child; } @Override @@ -80,7 +80,7 @@ @Child private AbstractTestNode child; public CatchSlowPathAndControlFlowExceptionTestNode(AbstractTestNode child) { - this.child = adoptChild(child); + this.child = child; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -85,7 +85,7 @@ } protected StructuredGraph partialEval(RootNode root, Arguments arguments, final Assumptions assumptions, final boolean canonicalizeReads) { - final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root); + final OptimizedCallTargetImpl compilable = (OptimizedCallTargetImpl) Truffle.getRuntime().createCallTarget(root); // Executed AST so that all classes are loaded and initialized. compilable.call(null, arguments); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/AddTestNode.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/AddTestNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/AddTestNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,8 +30,8 @@ @Child private AbstractTestNode right; public AddTestNode(AbstractTestNode left, AbstractTestNode right) { - this.left = adoptChild(left); - this.right = adoptChild(right); + this.left = left; + this.right = right; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,7 +30,7 @@ @Children private final AbstractTestNode[] statements; public BlockTestNode(AbstractTestNode[] statements) { - this.statements = adoptChildren(statements); + this.statements = statements; } @ExplodeLoop diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LoopTestNode.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LoopTestNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LoopTestNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -31,7 +31,7 @@ public LoopTestNode(int numberOfIterations, AbstractTestNode child) { this.numberOfIterations = numberOfIterations; - this.child = adoptChild(child); + this.child = child; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Sun Mar 30 16:08:33 2014 +0200 @@ -132,11 +132,18 @@ ensureProfiling(reprofile, reprofile); } - void reportInterpreterCall() { + public void reportInterpreterCall() { callCount++; callAndLoopCount++; } + void reportInlinedCall() { + callCount++; + callAndLoopCount++; + compilationCallThreshold++; + compilationCallAndLoopThreshold++; + } + void reportInterpreterCalls(int calls) { this.callCount += calls; this.callAndLoopCount += calls; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Sun Mar 30 16:08:33 2014 +0200 @@ -55,7 +55,7 @@ @Override public T getArguments(Class clazz) { - return CompilerDirectives.unsafeCast(arguments, clazz, true); + return CompilerDirectives.unsafeCast(arguments, clazz, true, true); } @Override @@ -85,15 +85,15 @@ } private Object[] getLocals() { - return CompilerDirectives.unsafeCast(locals, Object[].class, true); + return CompilerDirectives.unsafeCast(locals, Object[].class, true, true); } private long[] getPrimitiveLocals() { - return CompilerDirectives.unsafeCast(this.primitiveLocals, long[].class, true); + return CompilerDirectives.unsafeCast(this.primitiveLocals, long[].class, true, true); } private byte[] getTags() { - return CompilerDirectives.unsafeCast(tags, byte[].class, true); + return CompilerDirectives.unsafeCast(tags, byte[].class, true, true); } private Object getObjectUnsafe(FrameSlot slot) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Sun Mar 30 16:08:33 2014 +0200 @@ -77,7 +77,7 @@ if (truffleCompiler == null) { truffleCompiler = new TruffleCompilerImpl(); } - return new OptimizedCallTarget(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode)); + return new OptimizedCallTargetImpl(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode)); } public CallNode createCallNode(CallTarget target) { @@ -90,7 +90,7 @@ @Override public VirtualFrame createVirtualFrame(PackedFrame caller, Arguments arguments, FrameDescriptor frameDescriptor) { - return OptimizedCallTarget.createFrame(frameDescriptor, caller, arguments); + return OptimizedCallTargetImpl.createFrame(frameDescriptor, caller, arguments); } @Override @@ -173,7 +173,7 @@ private static Method getCallMethod() { Method method; try { - method = OptimizedCallTarget.class.getDeclaredMethod("call", new Class[]{PackedFrame.class, Arguments.class}); + method = OptimizedCallTargetImpl.class.getDeclaredMethod("call", new Class[]{PackedFrame.class, Arguments.class}); } catch (NoSuchMethodException | SecurityException e) { throw GraalInternalError.shouldNotReachHere(); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.truffle; import java.util.*; -import java.util.concurrent.atomic.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; @@ -34,7 +33,7 @@ /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. */ -abstract class OptimizedCallNode extends DefaultCallNode { +public abstract class OptimizedCallNode extends DefaultCallNode { protected int callCount; @@ -79,7 +78,7 @@ throw new IllegalStateException("CallNode must be adopted before it is split."); } - return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), getCurrentCallTarget().getRootNode(), callCount)); + return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), callCount)); } public static OptimizedCallNode create(OptimizedCallTarget target) { @@ -126,17 +125,11 @@ if (!isSplittable()) { return false; } - int nodeCount = NodeUtil.countNodes(getCallTarget().getRootNode(), null, false); + int nodeCount = NodeUtil.countNodes(getCallTarget().getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, false); if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { return false; } - // // is the only call target -> do not split - // if (getCallTarget().getRootNode().getCachedCallNodes().size() == 1 && - // getCallTarget().getRootNode().getCachedCallNodes().contains(this)) { - // return false; - // } - // disable recursive splitting for now OptimizedCallTarget splitTarget = getCallTarget(); List compilationRoots = OptimizedCallNodeProfile.findCompilationRoots(this); @@ -160,17 +153,11 @@ } private boolean isMaxSingleCall() { - final AtomicInteger count = new AtomicInteger(0); - getCurrentCallTarget().getRootNode().accept(new NodeVisitor() { - - public boolean visit(Node node) { - if (node instanceof CallNode) { - return count.incrementAndGet() > 1; - } - return true; + return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() { + public boolean isCounted(Node node) { + return node instanceof CallNode; } - }); - return count.get() <= 1; + }) <= 1; } private int countPolymorphic() { @@ -224,12 +211,10 @@ private static final class InlinedOptimizedCallNode extends OptimizedCallNode { - private final RootNode inlinedRoot; private final OptimizedCallTarget splittedTarget; - public InlinedOptimizedCallNode(OptimizedCallTarget target, OptimizedCallTarget splittedTarget, RootNode inlinedRoot, int callCount) { + public InlinedOptimizedCallNode(OptimizedCallTarget target, OptimizedCallTarget splittedTarget, int callCount) { super(target); - this.inlinedRoot = inlinedRoot; this.splittedTarget = splittedTarget; this.callCount = callCount; } @@ -239,7 +224,7 @@ if (CompilerDirectives.inInterpreter()) { callCount++; } - return inlinedRoot.execute(Truffle.getRuntime().createVirtualFrame(caller, arguments, inlinedRoot.getFrameDescriptor())); + return getCurrentCallTarget().callInlined(caller, arguments); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,11 +27,13 @@ import java.util.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeUtil.*; public class OptimizedCallNodeProfile implements TruffleInliningProfile { + static final CountFilter COUNT_FILTER = new CountFilter(); + private static final String REASON_RECURSION = "recursion"; - private static final String REASON_FREQUENCY_CUTOFF = "frequency < " + TruffleInliningMinFrequency.getValue(); private static final String REASON_MAXIMUM_NODE_COUNT = "shallowTargetCount > " + TruffleInliningMaxCalleeSize.getValue(); private static final String REASON_MAXIMUM_TOTAL_NODE_COUNT = "inlinedTotalCount > " + TruffleInliningMaxCallerSize.getValue(); @@ -43,17 +45,34 @@ private final int targetShallowNodeCount; private final double averageFrequency; private final double score; + private final boolean leaf; private String reason; public OptimizedCallNodeProfile(OptimizedCallTarget target, OptimizedCallNode callNode) { this.callNode = callNode; RootNode inlineRoot = callNode.getCurrentCallTarget().getRootNode(); this.callTarget = target; - this.targetShallowNodeCount = NodeUtil.countNodes(inlineRoot, null, false); - this.targetDeepNodeCount = NodeUtil.countNodes(inlineRoot, null, true); + this.targetShallowNodeCount = NodeUtil.countNodes(inlineRoot, COUNT_FILTER, false); + this.targetDeepNodeCount = NodeUtil.countNodes(inlineRoot, COUNT_FILTER, true); this.compilationRoots = findCompilationRoots(callNode); this.averageFrequency = calculateFrequency(); this.score = calculateScore(); + this.leaf = calculateLeaf(); + + } + + private boolean calculateLeaf() { + return NodeUtil.countNodes(callNode.getCurrentRootNode(), new NodeCountFilter() { + public boolean isCounted(Node node) { + if (node instanceof CallNode) { + CallNode childCall = (CallNode) node; + if (!childCall.isInlined()) { + return true; + } + } + return false; + } + }, true) <= 0; } private double calculateFrequency() { @@ -69,7 +88,7 @@ } public double calculateScore() { - return averageFrequency / targetDeepNodeCount; + return averageFrequency / Math.max(1, targetDeepNodeCount); } public boolean isInliningAllowed() { @@ -84,18 +103,12 @@ } } - // frequency cut-off - if (averageFrequency < TruffleInliningMinFrequency.getValue() && targetDeepNodeCount > TruffleInliningTrivialSize.getValue()) { - reason = REASON_FREQUENCY_CUTOFF; - return false; - } - if (targetShallowNodeCount > TruffleInliningMaxCalleeSize.getValue()) { reason = REASON_MAXIMUM_NODE_COUNT; return false; } - this.targetDeepNodeCount = NodeUtil.countNodes(inlineTarget.getRootNode(), null, true); + this.targetDeepNodeCount = NodeUtil.countNodes(inlineTarget.getRootNode(), COUNT_FILTER, true); // The maximum total node count cannot be cached since it may change during inlining. int nextNodeCount = calculateInlinedTotalNodeCount(getCallNode()); if (nextNodeCount > TruffleInliningMaxCallerSize.getValue()) { @@ -116,6 +129,20 @@ return currentNodeCount; } + static class CountFilter implements NodeCountFilter { + public boolean isCounted(Node node) { + return countNode(node) >= 1; + } + } + + static int countNode(Node node) { + NodeCost cost = node.getCost(); + if (cost != null && cost != NodeCost.NONE && cost != NodeCost.UNINITIALIZED) { + return 1; + } + return 0; + } + private static class TotalNodeCountVisitor implements NodeVisitor { private final OptimizedCallNode inlinedNode; @@ -129,7 +156,7 @@ } public boolean visit(Node node) { - count++; + count += countNode(node); if (node instanceof OptimizedCallNode) { OptimizedCallNode callNode = ((OptimizedCallNode) node); if (callNode == inlinedNode) { @@ -178,17 +205,13 @@ for (OptimizedCallNode c : callStack) { int childCallCount = c.getCallCount(); frequency *= childCallCount / (double) parentCallCount; - if (c.isInlined() || c.isSplit()) { - parentCallCount = childCallCount; - } else { - parentCallCount = c.getCurrentCallTarget().getCompilationProfile().getCallCount(); - } + parentCallCount = c.getCurrentCallTarget().getCompilationProfile().getCallCount(); } return frequency; } double calculateSimpleFrequency() { - return callNode.getCallCount() / (double) callTarget.getCompilationProfile().getCallCount(); + return callNode.getCallCount() / (double) ((OptimizedCallTarget) callNode.getRootNode().getCallTarget()).getCompilationProfile().getCallCount(); } static List findCompilationRoots(Node call) { @@ -208,7 +231,11 @@ public int compareTo(TruffleInliningProfile o) { if (o instanceof OptimizedCallNodeProfile) { - return Double.compare(((OptimizedCallNodeProfile) o).getScore(), getScore()); + int cmp = Boolean.compare(((OptimizedCallNodeProfile) o).leaf, leaf); + if (cmp == 0) { + return Double.compare(((OptimizedCallNodeProfile) o).getScore(), getScore()); + } + return cmp; } return 0; } @@ -221,7 +248,7 @@ properties.put("inlinedTotalCount", calculateInlinedTotalNodeCount(getCallNode())); properties.put("score", score); properties.put("frequency", averageFrequency); - properties.put("callCount", callNode.getCallCount()); + properties.put("leaf", leaf); properties.put("reason", reason); return properties; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Sun Mar 30 16:08:33 2014 +0200 @@ -26,7 +26,6 @@ import java.io.*; import java.util.*; -import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; @@ -39,34 +38,27 @@ /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. */ -public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, ReplaceObserver { +public abstract class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, ReplaceObserver { - private static final PrintStream OUT = TTY.out().out(); + protected static final PrintStream OUT = TTY.out().out(); - private InstalledCode installedCode; - private Future installedCodeTask; - private boolean compilationEnabled; + protected InstalledCode installedCode; + protected boolean compilationEnabled; private boolean inlined; - private int callCount; + protected int callCount; - private final TruffleCompiler compiler; - private final CompilationProfile compilationProfile; - private final CompilationPolicy compilationPolicy; - private final SpeculationLog speculationLog = new SpeculationLog(); + protected final CompilationProfile compilationProfile; + protected final CompilationPolicy compilationPolicy; + private SpeculationLog speculationLog = new SpeculationLog(); private OptimizedCallTarget splitSource; - OptimizedCallTarget(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) { + public OptimizedCallTarget(RootNode rootNode, int invokeCounter, int compilationThreshold, boolean compilationEnabled, CompilationPolicy compilationPolicy) { super(rootNode); - this.compiler = compiler; - this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); - if (TruffleUseTimeForCompilationDecision.getValue()) { - compilationPolicy = new TimedCompilationPolicy(); - } else { - compilationPolicy = new DefaultCompilationPolicy(); - } this.compilationEnabled = compilationEnabled; + this.compilationPolicy = compilationPolicy; + this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); if (TruffleCallTargetProfiling.getValue()) { registerCallTarget(this); } @@ -92,87 +84,18 @@ return superString; } - public boolean isOptimized() { - return installedCode != null || installedCodeTask != null; - } - - @CompilerDirectives.SlowPath - @Override - public Object call(PackedFrame caller, Arguments args) { - return callHelper(caller, args); - } - - private Object callHelper(PackedFrame caller, Arguments args) { - if (installedCode != null && installedCode.isValid()) { - reinstallCallMethodShortcut(); - } - if (TruffleCallTargetProfiling.getValue()) { - callCount++; - } - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, installedCode != null)) { - try { - return installedCode.execute(this, caller, args); - } catch (InvalidInstalledCodeException ex) { - return compiledCodeInvalidated(caller, args); - } - } else { - return interpreterCall(caller, args); - } - } - - private static void reinstallCallMethodShortcut() { - if (TraceTruffleCompilation.getValue()) { - OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut."); - } - GraalTruffleRuntime.installOptimizedCallTargetCallMethod(); - } - public CompilationProfile getCompilationProfile() { return compilationProfile; } - private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { - invalidate(null, null, "Compiled code invalidated"); - return call(caller, args); - } - - private void invalidate(Node oldNode, Node newNode, CharSequence reason) { - InstalledCode m = this.installedCode; - if (m != null) { - CompilerAsserts.neverPartOfCompilation(); - installedCode = null; - compilationProfile.reportInvalidated(); - logOptimizedInvalidated(this, oldNode, newNode, reason); - } - cancelInstalledTask(oldNode, newNode, reason); - } + @Override + public abstract Object call(PackedFrame caller, Arguments args); - private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) { - Future task = this.installedCodeTask; - if (task != null) { - task.cancel(true); - this.installedCodeTask = null; - logOptimizingUnqueued(this, oldNode, newNode, reason); - compilationProfile.reportInvalidated(); + public Object callInlined(PackedFrame caller, Arguments arguments) { + if (CompilerDirectives.inInterpreter()) { + compilationProfile.reportInlinedCall(); } - } - - private Object interpreterCall(PackedFrame caller, Arguments args) { - CompilerAsserts.neverPartOfCompilation(); - compilationProfile.reportInterpreterCall(); - - if (compilationEnabled && compilationPolicy.shouldCompile(compilationProfile)) { - InstalledCode code = compile(); - if (code != null && code.isValid()) { - this.installedCode = code; - try { - return code.execute(this, caller, args); - } catch (InvalidInstalledCodeException ex) { - return compiledCodeInvalidated(caller, args); - } - } - } - return executeHelper(caller, args); + return executeHelper(caller, arguments); } public void performInlining() { @@ -196,8 +119,8 @@ while (callSite != null) { if (callSite.isInliningAllowed()) { OptimizedCallNode callNode = callSite.getCallNode(); + RootNode inlinedRoot = callNode.inlineImpl().getCurrentRootNode(); logInlined(this, callSite); - RootNode inlinedRoot = callNode.inlineImpl().getCurrentRootNode(); assert inlinedRoot != null; queueCallSitesForInlining(this, inlinedRoot, visitedCallNodes, queue); } else { @@ -227,61 +150,22 @@ }); } - private boolean isCompiling() { - Future codeTask = this.installedCodeTask; - if (codeTask != null) { - if (codeTask.isCancelled()) { - installedCodeTask = null; - return false; - } - return true; - } - return false; + protected boolean shouldCompile() { + return compilationPolicy.shouldCompile(compilationProfile); } - public InstalledCode compile() { - if (isCompiling()) { - if (installedCodeTask.isDone()) { - return receiveInstalledCode(); - } - return null; - } else { - performInlining(); - logOptimizingQueued(this); - this.installedCodeTask = compiler.compile(this); - if (!TruffleBackgroundCompilation.getValue()) { - return receiveInstalledCode(); - } - } - return null; + protected static boolean shouldInline() { + return TruffleFunctionInlining.getValue(); } - private InstalledCode receiveInstalledCode() { - try { - return installedCodeTask.get(); - } catch (InterruptedException | ExecutionException e) { - compilationEnabled = false; - logOptimizingFailed(this, e.getMessage()); - if (e.getCause() instanceof BailoutException) { - // Bailout => move on. - } else { - if (TraceTruffleCompilationExceptions.getValue()) { - e.printStackTrace(OUT); - } - if (TruffleCompilationExceptionsAreFatal.getValue()) { - System.exit(-1); - } - } - return null; - } - } + protected abstract void invalidate(Node oldNode, Node newNode, CharSequence reason); public Object executeHelper(PackedFrame caller, Arguments args) { VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), caller, args); return getRootNode().execute(frame); } - protected static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { + public static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { return new FrameWithoutBoxing(descriptor, caller, args); } @@ -334,7 +218,7 @@ } } - private static void logInlined(@SuppressWarnings("unused") final OptimizedCallTarget target, TruffleInliningProfile callSite) { + private static void logInlined(final OptimizedCallTarget target, TruffleInliningProfile callSite) { if (TraceTruffleInliningDetails.getValue() || TraceTruffleInlining.getValue()) { log(2, "inline success", callSite.getCallNode().getCurrentCallTarget().toString(), callSite.getDebugProperties()); @@ -348,13 +232,23 @@ OptimizedCallNode callNode = ((OptimizedCallNode) node); RootNode inlinedRoot = callNode.getCurrentRootNode(); - if (inlinedRoot != null && callNode.isInlined()) { + if (inlinedRoot != null) { Map properties = new LinkedHashMap<>(); addASTSizeProperty(callNode.getCurrentRootNode(), properties); - log(2 + (depth * 2), "inline success", callNode.getCurrentCallTarget().toString(), properties); - depth++; - inlinedRoot.accept(this); - depth--; + properties.putAll(callNode.createInliningProfile(target).getDebugProperties()); + String message; + if (callNode.isInlined()) { + message = "inline success"; + } else { + message = "inline dispatch"; + } + log(2 + (depth * 2), message, callNode.getCurrentCallTarget().toString(), properties); + + if (callNode.isInlined()) { + depth++; + inlinedRoot.accept(this); + depth--; + } } } return true; @@ -376,13 +270,13 @@ } } - private static void logOptimizingQueued(OptimizedCallTarget target) { + protected static void logOptimizingQueued(OptimizedCallTarget target) { if (TraceTruffleCompilationDetails.getValue()) { log(0, "opt queued", target.toString(), target.getDebugProperties()); } } - private static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { + protected static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { if (TraceTruffleCompilationDetails.getValue()) { Map properties = new LinkedHashMap<>(); addReplaceProperties(properties, oldNode, newNode); @@ -405,7 +299,7 @@ } } - private static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { + protected static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { if (TraceTruffleCompilation.getValue()) { Map properties = new LinkedHashMap<>(); addReplaceProperties(properties, oldNode, newNode); @@ -414,7 +308,7 @@ } } - private static void logOptimizingFailed(OptimizedCallTarget callSite, CharSequence reason) { + protected static void logOptimizingFailed(OptimizedCallTarget callSite, CharSequence reason) { Map properties = new LinkedHashMap<>(); properties.put("Reason", reason); log(0, "opt fail", callSite.toString(), properties); @@ -473,7 +367,7 @@ } }, true); - String value = String.format("%4d (%d/%d)", NodeUtil.countNodes(target.getRootNode(), null, true), // + String value = String.format("%4d (%d/%d)", NodeUtil.countNodes(target.getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, true), // polymorphicCount, megamorphicCount); // properties.put("ASTSize", value); @@ -533,8 +427,8 @@ continue; } - int nodeCount = NodeUtil.countNodes(callTarget.getRootNode(), null, true); - int inlinedCallSiteCount = countInlinedNodes(callTarget.getRootNode()); + int nodeCount = NodeUtil.countNodes(callTarget.getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, false); + int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.getRootNode(), OptimizedCallNodeProfile.COUNT_FILTER, true); String comment = callTarget.installedCode == null ? " int" : ""; comment += callTarget.compilationEnabled ? "" : " fail"; OUT.printf("%-50s | %10d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, nodeCount, @@ -548,21 +442,6 @@ OUT.printf("%-50s | %10d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNodeCount, totalInvalidationCount); } - private static int countInlinedNodes(Node rootNode) { - List callers = NodeUtil.findAllNodeInstances(rootNode, CallNode.class); - int count = 0; - for (CallNode callNode : callers) { - if (callNode.isInlined()) { - count++; - RootNode root = callNode.getCurrentRootNode(); - if (root != null) { - count += countInlinedNodes(root); - } - } - } - return count; - } - private static void registerCallTarget(OptimizedCallTarget callTarget) { callTargets.put(callTarget, 0); } @@ -581,4 +460,5 @@ }); } } + } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetImpl.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2013, 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.truffle; + +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; + +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Call target for running truffle on a standard VM (and not in SubstrateVM). + */ +public final class OptimizedCallTargetImpl extends OptimizedCallTarget { + + protected final TruffleCompiler compiler; + private Future installedCodeTask; + + OptimizedCallTargetImpl(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) { + super(rootNode, invokeCounter, compilationThreshold, compilationEnabled, TruffleUseTimeForCompilationDecision.getValue() ? new TimedCompilationPolicy() : new DefaultCompilationPolicy()); + this.compiler = compiler; + } + + public boolean isOptimized() { + return installedCode != null || installedCodeTask != null; + } + + @CompilerDirectives.SlowPath + @Override + public Object call(PackedFrame caller, Arguments args) { + return callHelper(caller, args); + } + + private Object callHelper(PackedFrame caller, Arguments args) { + if (installedCode != null && installedCode.isValid()) { + reinstallCallMethodShortcut(); + } + if (TruffleCallTargetProfiling.getValue()) { + callCount++; + } + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, installedCode != null)) { + try { + return installedCode.execute(this, caller, args); + } catch (InvalidInstalledCodeException ex) { + return compiledCodeInvalidated(caller, args); + } + } else { + return interpreterCall(caller, args); + } + } + + private static void reinstallCallMethodShortcut() { + if (TraceTruffleCompilation.getValue()) { + OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut."); + } + GraalTruffleRuntime.installOptimizedCallTargetCallMethod(); + } + + private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { + invalidate(null, null, "Compiled code invalidated"); + return call(caller, args); + } + + @Override + protected void invalidate(Node oldNode, Node newNode, CharSequence reason) { + InstalledCode m = this.installedCode; + if (m != null) { + CompilerAsserts.neverPartOfCompilation(); + installedCode = null; + compilationProfile.reportInvalidated(); + logOptimizedInvalidated(this, oldNode, newNode, reason); + } + cancelInstalledTask(oldNode, newNode, reason); + } + + private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) { + Future task = this.installedCodeTask; + if (task != null) { + task.cancel(true); + this.installedCodeTask = null; + logOptimizingUnqueued(this, oldNode, newNode, reason); + compilationProfile.reportInvalidated(); + } + } + + private Object interpreterCall(PackedFrame caller, Arguments args) { + CompilerAsserts.neverPartOfCompilation(); + compilationProfile.reportInterpreterCall(); + + if (compilationEnabled && compilationPolicy.shouldCompile(compilationProfile)) { + InstalledCode code = compile(); + if (code != null && code.isValid()) { + this.installedCode = code; + try { + return code.execute(this, caller, args); + } catch (InvalidInstalledCodeException ex) { + return compiledCodeInvalidated(caller, args); + } + } + } + return executeHelper(caller, args); + } + + private boolean isCompiling() { + Future codeTask = this.installedCodeTask; + if (codeTask != null) { + if (codeTask.isCancelled()) { + installedCodeTask = null; + return false; + } + return true; + } + return false; + } + + public InstalledCode compile() { + if (isCompiling()) { + if (installedCodeTask.isDone()) { + return receiveInstalledCode(); + } + return null; + } else { + performInlining(); + logOptimizingQueued(this); + this.installedCodeTask = compiler.compile(this); + if (!TruffleBackgroundCompilation.getValue()) { + return receiveInstalledCode(); + } + return null; + } + } + + private InstalledCode receiveInstalledCode() { + try { + return installedCodeTask.get(); + } catch (InterruptedException | ExecutionException e) { + compilationEnabled = false; + logOptimizingFailed(this, e.getMessage()); + if (e.getCause() instanceof BailoutException) { + // Bailout => move on. + } else { + if (TraceTruffleCompilationExceptions.getValue()) { + e.printStackTrace(OUT); + } + if (TruffleCompilationExceptionsAreFatal.getValue()) { + System.exit(-1); + } + } + return null; + } + } + +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Sun Mar 30 16:08:33 2014 +0200 @@ -37,7 +37,6 @@ import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.Node; import com.oracle.graal.graph.spi.*; -import com.oracle.graal.java.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -57,7 +56,6 @@ import com.oracle.graal.truffle.phases.*; import com.oracle.graal.virtual.phases.ea.*; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; /** @@ -66,25 +64,17 @@ public class PartialEvaluator { private final Providers providers; - private final ResolvedJavaMethod executeHelperMethod; private final CanonicalizerPhase canonicalizer; - private final GraphBuilderConfiguration config; private Set constantReceivers; private final TruffleCache truffleCache; private final ResolvedJavaType frameType; - public PartialEvaluator(Providers providers, TruffleCache truffleCache, GraphBuilderConfiguration config) { + public PartialEvaluator(Providers providers, TruffleCache truffleCache) { this.providers = providers; CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(providers.getMetaAccess(), providers.getConstantReflection()); this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue(), customCanonicalizer); - this.config = config; this.truffleCache = truffleCache; this.frameType = providers.getMetaAccess().lookupJavaType(FrameWithoutBoxing.class); - try { - executeHelperMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class)); - } catch (NoSuchMethodException ex) { - throw new RuntimeException(ex); - } } public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) { @@ -98,10 +88,10 @@ constantReceivers = new HashSet<>(); } - final StructuredGraph graph = new StructuredGraph(executeHelperMethod); + final StructuredGraph graph = truffleCache.createRootGraph(); + assert graph != null : "no graph for root method"; - try (Scope s = Debug.scope("createGraph", graph)) { - new GraphBuilderPhase.Instance(providers.getMetaAccess(), config, TruffleCompilerImpl.Optimizations).apply(graph); + try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph.method())) { // Replace thisNode with constant. ParameterNode thisNode = graph.getParameter(0); @@ -187,42 +177,54 @@ changed = false; for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class)) { InvokeKind kind = methodCallTargetNode.invokeKind(); - if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || isFrame(methodCallTargetNode.receiver())))) { - if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) { - ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); - constantReceivers.add(constantNode.asConstant()); - } - Replacements replacements = providers.getReplacements(); - Class macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod()); - if (macroSubstitution != null) { - InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); - changed = true; - continue; - } + try (Indent id1 = Debug.logAndIndent("try inlining %s, kind = %s", methodCallTargetNode.targetMethod(), kind)) { + if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || isFrame(methodCallTargetNode.receiver())))) { + if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) { + ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); + constantReceivers.add(constantNode.asConstant()); + } + Replacements replacements = providers.getReplacements(); + Class macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod()); + if (macroSubstitution != null) { + InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); + changed = true; + continue; + } + + if (TraceTruffleCompilationDetails.getValue() && kind == InvokeKind.Special) { + ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); + constantReceivers.add(constantNode.asConstant()); + } + + StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); + if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers())) { + inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext); + } - StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); - if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && - methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null) { - inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext); - } + if (inlineGraph != null) { + try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) { - if (inlineGraph != null) { - int nodeCountBefore = graph.getNodeCount(); - Mark mark = graph.getMark(); - if (TraceTruffleExpansion.getValue()) { - expansionLogger.preExpand(methodCallTargetNode, inlineGraph); + int nodeCountBefore = graph.getNodeCount(); + Mark mark = graph.getMark(); + if (TraceTruffleExpansion.getValue()) { + expansionLogger.preExpand(methodCallTargetNode, inlineGraph); + } + List invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot(); + // try (Indent in2 = Debug.logAndIndent(false, "do inlining")) { + Map inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false); + if (TraceTruffleExpansion.getValue()) { + expansionLogger.postExpand(inlined); + } + // } + if (Debug.isDumpEnabled()) { + Debug.log("dump enabled"); + int nodeCountAfter = graph.getNodeCount(); + Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter); + } + canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark); + changed = true; + } } - List invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot(); - Map inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false); - if (TraceTruffleExpansion.getValue()) { - expansionLogger.postExpand(inlined); - } - if (Debug.isDumpEnabled()) { - int nodeCountAfter = graph.getNodeCount(); - Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter); - } - canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark); - changed = true; } } @@ -249,8 +251,8 @@ StructuredGraph graph = truffleCache.lookup(targetMethod, arguments, assumptions, canonicalizer); - if (targetMethod.getAnnotation(ExplodeLoop.class) != null) { - assert graph.hasLoops(); + if (graph != null && targetMethod.getAnnotation(ExplodeLoop.class) != null) { + assert graph.hasLoops() : graph + " does not contain a loop"; final StructuredGraph graphCopy = graph.copy(); final List modifiedNodes = new ArrayList<>(); for (ParameterNode param : graphCopy.getNodes(ParameterNode.class)) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Sun Mar 30 16:08:33 2014 +0200 @@ -44,12 +44,14 @@ this.constantReflection = constantReflection; } + private static final Unsafe unsafe = Unsafe.getUnsafe(); + @Override public Node canonicalize(Node node) { if (node instanceof LoadFieldNode) { LoadFieldNode loadFieldNode = (LoadFieldNode) node; if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) { - if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.kind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) || + if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.getKind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) || loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) { Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant()); assert verifyFieldValue(loadFieldNode.field(), constant); @@ -62,8 +64,8 @@ Object array = loadIndexedNode.array().asConstant().asObject(); long index = loadIndexedNode.index().asConstant().asLong(); if (index >= 0 && index < Array.getLength(array)) { - int arrayBaseOffset = Unsafe.getUnsafe().arrayBaseOffset(array.getClass()); - int arrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(array.getClass()); + int arrayBaseOffset = unsafe.arrayBaseOffset(array.getClass()); + int arrayIndexScale = unsafe.arrayIndexScale(array.getClass()); Constant constant = constantReflection.readUnsafeConstant(loadIndexedNode.elementKind(), array, arrayBaseOffset + index * arrayIndexScale, loadIndexedNode.elementKind() == Kind.Object); return ConstantNode.forConstant(constant, metaAccess, loadIndexedNode.graph()); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TimedCompilationPolicy.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TimedCompilationPolicy.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TimedCompilationPolicy.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,6 +24,8 @@ import static com.oracle.graal.truffle.TruffleCompilerOptions.*; +import java.io.*; + public class TimedCompilationPolicy extends DefaultCompilationPolicy { @Override @@ -39,9 +41,8 @@ // maybe introduce another method? profile.reportTiminingFailed(timestamp); if (TruffleCompilationDecisionTimePrintFail.getValue()) { - // Checkstyle: stop - System.out.println(profile.getName() + ": timespan " + (timespan / 1000000) + " ms larger than threshold"); - // Checkstyle: resume + PrintStream out = System.out; + out.println(profile.getName() + ": timespan " + (timespan / 1000000) + " ms larger than threshold"); } } return false; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,232 +22,21 @@ */ package com.oracle.graal.truffle; -import static com.oracle.graal.phases.GraalOptions.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.Map.Entry; - import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.truffle.phases.*; -import com.oracle.graal.virtual.phases.ea.*; -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Implementation of a cache for Truffle graphs for improving partial evaluation time. - */ -public final class TruffleCache { - - private final Providers providers; - private final GraphBuilderConfiguration config; - private final OptimisticOptimizations optimisticOptimizations; - - private final HashMap, StructuredGraph> cache = new HashMap<>(); - private final HashMap, Long> lastUsed = new HashMap<>(); - private final StructuredGraph markerGraph = new StructuredGraph(); - private final ResolvedJavaType stringBuilderClass; - private long counter; - - public TruffleCache(Providers providers, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations) { - this.providers = providers; - this.config = config; - this.optimisticOptimizations = optimisticOptimizations; - this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class); - } - - @SuppressWarnings("unused") - public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) { - List key = new ArrayList<>(arguments.size() + 1); - key.add(method); - for (ValueNode v : arguments) { - if (v.kind() == Kind.Object) { - key.add(v.stamp()); - } - } - StructuredGraph resultGraph = cache.get(key); - if (resultGraph != null) { - lastUsed.put(key, counter++); - return resultGraph; - } - - if (resultGraph == markerGraph) { - // Avoid recursive inline. - return null; - } - - if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) { - List lastUsedList = new ArrayList<>(); - for (long l : lastUsed.values()) { - lastUsedList.add(l); - } - Collections.sort(lastUsedList); - long mid = lastUsedList.get(lastUsedList.size() / 2); - - List> toRemoveList = new ArrayList<>(); - for (Entry, Long> entry : lastUsed.entrySet()) { - if (entry.getValue() < mid) { - toRemoveList.add(entry.getKey()); - } - } - - for (List entry : toRemoveList) { - cache.remove(entry); - lastUsed.remove(entry); - } - } - - lastUsed.put(key, counter++); - cache.put(key, markerGraph); - try (Scope s = Debug.scope("TruffleCache", new Object[]{providers.getMetaAccess(), method})) { - - final StructuredGraph graph = new StructuredGraph(method); - final PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false)); - Mark mark = graph.getMark(); - new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph); - - for (ParameterNode param : graph.getNodes(ParameterNode.class)) { - if (param.kind() == Kind.Object) { - ValueNode actualArgument = arguments.get(param.index()); - param.setStamp(param.stamp().join(actualArgument.stamp())); - } - } - - // Intrinsify methods. - new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph); - - // Convert deopt to guards. - new ConvertDeoptimizeToGuardPhase().apply(graph); - - CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!ImmutableCode.getValue()); - PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase); +public interface TruffleCache { - while (true) { - - partialEscapePhase.apply(graph, phaseContext); - - // Conditional elimination. - ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess()); - conditionalEliminationPhase.apply(graph); - - // Canonicalize / constant propagate. - canonicalizerPhase.apply(graph, phaseContext); - - boolean inliningProgress = false; - for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) { - if (!graph.getMark().equals(mark)) { - // Make sure macro substitutions such as - // CompilerDirectives.transferToInterpreter get processed first. - for (Node newNode : graph.getNewNodes(mark)) { - if (newNode instanceof MethodCallTargetNode) { - MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode; - Class macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod()); - if (macroSubstitution != null) { - InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); - } else { - tryCutOffRuntimeExceptions(methodCallTargetNode); - } - } - } - mark = graph.getMark(); - } - if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) { - inliningProgress = true; - List canonicalizerUsages = new ArrayList(); - for (Node n : methodCallTarget.invoke().asNode().usages()) { - if (n instanceof Canonicalizable) { - canonicalizerUsages.add(n); - } - } - List argumentSnapshot = methodCallTarget.arguments().snapshot(); - Mark beforeInvokeMark = graph.getMark(); - expandInvoke(methodCallTarget); - for (Node arg : argumentSnapshot) { - if (arg != null && arg.recordsUsages()) { - for (Node argUsage : arg.usages()) { - if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) { - canonicalizerUsages.add(argUsage); - } - } - } - } - canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages); - } - } - - // Convert deopt to guards. - new ConvertDeoptimizeToGuardPhase().apply(graph); + /** + * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#executeHelper}. + */ + StructuredGraph createRootGraph(); - new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext); - - if (!inliningProgress) { - break; - } - } - - cache.put(key, graph); - if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) { - TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount())); - } - return graph; - } catch (Throwable e) { - throw Debug.handle(e); - } - - } - - private void expandInvoke(MethodCallTargetNode methodCallTargetNode) { - StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod()); - if (inlineGraph == null) { - inlineGraph = TruffleCache.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null); - } - if (inlineGraph == this.markerGraph) { - // Can happen for recursive calls. - throw GraphUtil.approxSourceException(methodCallTargetNode, new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() + - ", must annotate such calls with @CompilerDirectives.SlowPath!")); - } - Invoke invoke = methodCallTargetNode.invoke(); - InliningUtil.inline(invoke, inlineGraph, true); - } - - private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) { - if (methodCallTargetNode.targetMethod().isConstructor()) { - ResolvedJavaType runtimeException = providers.getMetaAccess().lookupJavaType(RuntimeException.class); - ResolvedJavaType controlFlowException = providers.getMetaAccess().lookupJavaType(ControlFlowException.class); - ResolvedJavaType exceptionType = Objects.requireNonNull(ObjectStamp.typeOrNull(methodCallTargetNode.receiver().stamp())); - if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) { - DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode)); - FixedNode invokeNode = methodCallTargetNode.invoke().asNode(); - invokeNode.replaceAtPredecessor(deoptNode); - GraphUtil.killCFG(invokeNode); - return true; - } - } - return false; - } - - private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) { - return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && - !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null && - methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null && - !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass); - } + /** + * Returns a cached graph for a method with given arguments. + */ + StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2013, 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.truffle; + +import static com.oracle.graal.phases.GraalOptions.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.Graph.Mark; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.truffle.phases.*; +import com.oracle.graal.virtual.phases.ea.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Implementation of a cache for Truffle graphs for improving partial evaluation time. + */ +public final class TruffleCacheImpl implements TruffleCache { + + private final Providers providers; + private final GraphBuilderConfiguration config; + private final GraphBuilderConfiguration configForRootGraph; + private final OptimisticOptimizations optimisticOptimizations; + + private final HashMap, StructuredGraph> cache = new HashMap<>(); + private final HashMap, Long> lastUsed = new HashMap<>(); + private final StructuredGraph markerGraph = new StructuredGraph(); + private final ResolvedJavaType stringBuilderClass; + private final ResolvedJavaMethod executeHelperMethod; + private long counter; + + public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRootGraph, OptimisticOptimizations optimisticOptimizations) { + this.providers = providers; + this.config = config; + this.configForRootGraph = configForRootGraph; + this.optimisticOptimizations = optimisticOptimizations; + this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class); + try { + executeHelperMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class)); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } + + public StructuredGraph createRootGraph() { + StructuredGraph graph = new StructuredGraph(executeHelperMethod); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRootGraph, TruffleCompilerImpl.Optimizations).apply(graph); + return graph; + } + + @SuppressWarnings("unused") + public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) { + + if (method.getAnnotation(CompilerDirectives.SlowPath.class) != null) { + return null; + } + + List key = new ArrayList<>(arguments.size() + 1); + key.add(method); + for (ValueNode v : arguments) { + if (v.getKind() == Kind.Object) { + key.add(v.stamp()); + } + } + StructuredGraph resultGraph = cache.get(key); + if (resultGraph != null) { + lastUsed.put(key, counter++); + return resultGraph; + } + + if (resultGraph == markerGraph) { + // Avoid recursive inline. + return null; + } + + if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) { + List lastUsedList = new ArrayList<>(); + for (long l : lastUsed.values()) { + lastUsedList.add(l); + } + Collections.sort(lastUsedList); + long mid = lastUsedList.get(lastUsedList.size() / 2); + + List> toRemoveList = new ArrayList<>(); + for (Entry, Long> entry : lastUsed.entrySet()) { + if (entry.getValue() < mid) { + toRemoveList.add(entry.getKey()); + } + } + + for (List entry : toRemoveList) { + cache.remove(entry); + lastUsed.remove(entry); + } + } + + lastUsed.put(key, counter++); + cache.put(key, markerGraph); + try (Scope s = Debug.scope("TruffleCache", providers.getMetaAccess(), method)) { + + final StructuredGraph graph = new StructuredGraph(method); + final PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false)); + Mark mark = graph.getMark(); + new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph); + + for (ParameterNode param : graph.getNodes(ParameterNode.class)) { + if (param.getKind() == Kind.Object) { + ValueNode actualArgument = arguments.get(param.index()); + param.setStamp(param.stamp().join(actualArgument.stamp())); + } + } + + // Intrinsify methods. + new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph); + + // Convert deopt to guards. + new ConvertDeoptimizeToGuardPhase().apply(graph); + + CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!ImmutableCode.getValue()); + PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase); + + while (true) { + + partialEscapePhase.apply(graph, phaseContext); + + // Conditional elimination. + ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess()); + conditionalEliminationPhase.apply(graph); + + // Canonicalize / constant propagate. + canonicalizerPhase.apply(graph, phaseContext); + + boolean inliningProgress = false; + for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) { + if (!graph.getMark().equals(mark)) { + // Make sure macro substitutions such as + // CompilerDirectives.transferToInterpreter get processed first. + for (Node newNode : graph.getNewNodes(mark)) { + if (newNode instanceof MethodCallTargetNode) { + MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode; + Class macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod()); + if (macroSubstitution != null) { + InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); + } else { + tryCutOffRuntimeExceptions(methodCallTargetNode); + } + } + } + mark = graph.getMark(); + } + if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) { + inliningProgress = true; + List canonicalizerUsages = new ArrayList(); + for (Node n : methodCallTarget.invoke().asNode().usages()) { + if (n instanceof Canonicalizable) { + canonicalizerUsages.add(n); + } + } + List argumentSnapshot = methodCallTarget.arguments().snapshot(); + Mark beforeInvokeMark = graph.getMark(); + expandInvoke(methodCallTarget); + for (Node arg : argumentSnapshot) { + if (arg != null && arg.recordsUsages()) { + for (Node argUsage : arg.usages()) { + if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) { + canonicalizerUsages.add(argUsage); + } + } + } + } + canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages); + } + } + + // Convert deopt to guards. + new ConvertDeoptimizeToGuardPhase().apply(graph); + + new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext); + + if (!inliningProgress) { + break; + } + } + + cache.put(key, graph); + if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) { + TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount())); + } + return graph; + } catch (Throwable e) { + throw Debug.handle(e); + } + + } + + private void expandInvoke(MethodCallTargetNode methodCallTargetNode) { + StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod()); + if (inlineGraph == null) { + inlineGraph = TruffleCacheImpl.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null); + } + if (inlineGraph == this.markerGraph) { + // Can happen for recursive calls. + throw GraphUtil.approxSourceException(methodCallTargetNode, new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() + + ", must annotate such calls with @CompilerDirectives.SlowPath!")); + } + Invoke invoke = methodCallTargetNode.invoke(); + InliningUtil.inline(invoke, inlineGraph, true); + } + + private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) { + if (methodCallTargetNode.targetMethod().isConstructor()) { + ResolvedJavaType runtimeException = providers.getMetaAccess().lookupJavaType(RuntimeException.class); + ResolvedJavaType controlFlowException = providers.getMetaAccess().lookupJavaType(ControlFlowException.class); + ResolvedJavaType exceptionType = Objects.requireNonNull(ObjectStamp.typeOrNull(methodCallTargetNode.receiver().stamp())); + if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) { + DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode)); + FixedNode invokeNode = methodCallTargetNode.invoke().asNode(); + invokeNode.replaceAtPredecessor(deoptNode); + GraphUtil.killCFG(invokeNode); + return true; + } + } + return false; + } + + private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) { + return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && + !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null && + methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null && + !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass); + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Sun Mar 30 16:08:33 2014 +0200 @@ -98,18 +98,19 @@ ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault(); eagerConfig.setSkippedExceptionTypes(skippedExceptionTypes); - this.truffleCache = new TruffleCache(providers, eagerConfig, TruffleCompilerImpl.Optimizations); - this.config = GraphBuilderConfiguration.getDefault(); this.config.setSkippedExceptionTypes(skippedExceptionTypes); - this.partialEvaluator = new PartialEvaluator(providers, truffleCache, config); + + this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations); + + this.partialEvaluator = new PartialEvaluator(providers, truffleCache); if (Debug.isEnabled()) { DebugEnvironment.initialize(System.out); } } - private static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { + public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); @@ -122,7 +123,7 @@ @Override public InstalledCode call() throws Exception { try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(compilable))) { - return compileMethodImpl(compilable); + return compileMethodImpl((OptimizedCallTargetImpl) compilable); } catch (Throwable e) { throw Debug.handle(e); } @@ -134,11 +135,11 @@ public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); - private InstalledCode compileMethodImpl(final OptimizedCallTarget compilable) { + private InstalledCode compileMethodImpl(final OptimizedCallTargetImpl compilable) { final StructuredGraph graph; if (TraceTruffleCompilation.getValue()) { - OptimizedCallTarget.logOptimizingStart(compilable); + OptimizedCallTargetImpl.logOptimizingStart(compilable); } if (TraceTruffleInliningTree.getValue()) { @@ -178,7 +179,7 @@ properties.put("CodeSize", code != null ? code.length : 0); properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection())); - OptimizedCallTarget.logOptimizingDone(compilable, properties); + OptimizedCallTargetImpl.logOptimizingDone(compilable, properties); } return compiledMethod; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Sun Mar 30 16:08:33 2014 +0200 @@ -58,7 +58,7 @@ @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit") public static final OptionValue TruffleInliningMaxCallerSize = new OptionValue<>(2250); @Option(help = "Skip inlining candidate if its tree size exceeds this limit") - public static final OptionValue TruffleInliningMaxCalleeSize = new OptionValue<>(250); + public static final OptionValue TruffleInliningMaxCalleeSize = new OptionValue<>(350); @Option(help = "Call frequency relative to call target") public static final OptionValue TruffleInliningMinFrequency = new OptionValue<>(0.3); @Option(help = "Allow inlining of less hot candidates if tree size is small") diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java Sun Mar 30 16:08:33 2014 +0200 @@ -30,7 +30,7 @@ /** * Enables a Truffle compilable to masquerade as a {@link JavaMethod} for use as a context value in - * {@linkplain Debug#scope(String, Object...) debug scopes}. + * {@linkplain Debug#scope(Object) debug scopes}. */ public class TruffleDebugJavaMethod implements JavaMethod { private final RootCallTarget compilable; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java Sun Mar 30 16:08:33 2014 +0200 @@ -43,7 +43,7 @@ } public void preExpand(MethodCallTargetNode callTarget, StructuredGraph inliningGraph) { - ResolvedJavaMethod sourceMethod = callTarget.invoke().getState().method(); + ResolvedJavaMethod sourceMethod = callTarget.invoke().stateAfter().method(); int sourceMethodBci = callTarget.invoke().bci(); ResolvedJavaMethod targetMethod = callTarget.targetMethod(); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Sun Mar 30 16:08:33 2014 +0200 @@ -47,17 +47,17 @@ this.graalReplacements = providers.getReplacements(); } - static Replacements makeInstance() { + public static Replacements makeInstance() { Providers graalProviders = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders(); Replacements truffleReplacements = new TruffleReplacements(graalProviders); truffleReplacements.registerSubstitutions(CompilerAssertsSubstitutions.class); truffleReplacements.registerSubstitutions(CompilerDirectivesSubstitutions.class); truffleReplacements.registerSubstitutions(ExactMathSubstitutions.class); - truffleReplacements.registerSubstitutions(UnexpectedResultExceptionSubstitutions.class); truffleReplacements.registerSubstitutions(FrameWithoutBoxingSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedAssumptionSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedCallTargetSubstitutions.class); + truffleReplacements.registerSubstitutions(OptimizedCallTargetImplSubstitutions.class); return truffleReplacements; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -34,7 +34,7 @@ } @Override - protected Value generateArithmetic(LIRGeneratorTool gen) { - return gen.emitAdd(gen.operand(getX()), gen.operand(getY())); + protected Value generateArithmetic(NodeLIRGeneratorTool gen) { + return gen.getLIRGeneratorTool().emitAdd(gen.operand(getX()), gen.operand(getY())); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,14 +23,12 @@ package com.oracle.graal.truffle.nodes.arithmetic; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public abstract class IntegerExactArithmeticSplitNode extends ControlSplitNode implements LIRGenLowerable { +public abstract class IntegerExactArithmeticSplitNode extends ControlSplitNode implements LIRLowerable { @Successor private AbstractBeginNode overflowSuccessor; @Successor private AbstractBeginNode next; @@ -72,12 +70,12 @@ } @Override - public void generate(LIRGenerator generator) { + public void generate(NodeLIRGeneratorTool generator) { generator.setResult(this, generateArithmetic(generator)); - generator.emitOverflowCheckBranch(generator.getLIRBlock(getOverflowSuccessor()), generator.getLIRBlock(getNext()), probability(getOverflowSuccessor())); + generator.emitOverflowCheckBranch(getOverflowSuccessor(), getNext(), probability(getOverflowSuccessor())); } - protected abstract Value generateArithmetic(LIRGeneratorTool generator); + protected abstract Value generateArithmetic(NodeLIRGeneratorTool generator); static void lower(LoweringTool tool, IntegerExactArithmeticNode node) { if (node.asNode().graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -34,7 +34,7 @@ } @Override - protected Value generateArithmetic(LIRGeneratorTool gen) { - return gen.emitMul(gen.operand(getX()), gen.operand(getY())); + protected Value generateArithmetic(NodeLIRGeneratorTool gen) { + return gen.getLIRGeneratorTool().emitMul(gen.operand(getX()), gen.operand(getY())); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -34,7 +34,7 @@ } @Override - protected Value generateArithmetic(LIRGeneratorTool gen) { - return gen.emitSub(gen.operand(getX()), gen.operand(getY())); + protected Value generateArithmetic(NodeLIRGeneratorTool gen) { + return gen.getLIRGeneratorTool().emitSub(gen.operand(getX()), gen.operand(getY())); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -75,7 +75,7 @@ int entryIndex = state.getVirtualObject().entryIndexForOffset(constantOffset); if (entryIndex != -1) { ValueNode entry = state.getEntry(entryIndex); - if (entry.kind() == kind() || state.getVirtualObject().entryKind(entryIndex) == accessKind) { + if (entry.getKind() == getKind() || state.getVirtualObject().entryKind(entryIndex) == accessKind) { tool.replaceWith(entry); } } diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -33,14 +33,15 @@ import com.oracle.truffle.api.*; /** - * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean)}. + * Macro node for method {@link CompilerDirectives#unsafeCast(Object, Class, boolean, boolean)}. */ public class UnsafeTypeCastMacroNode extends NeverPartOfCompilationNode implements Canonicalizable { - private static final int ARGUMENT_COUNT = 3; private static final int OBJECT_ARGUMENT_INDEX = 0; private static final int CLASS_ARGUMENT_INDEX = 1; private static final int CONDITION_ARGUMENT_INDEX = 2; + private static final int NONNULL_ARGUMENT_INDEX = 3; + private static final int ARGUMENT_COUNT = 4; public UnsafeTypeCastMacroNode(Invoke invoke) { super(invoke, "The class of the unsafe cast could not be reduced to a compile time constant."); @@ -50,7 +51,8 @@ @Override public Node canonical(CanonicalizerTool tool) { ValueNode classArgument = arguments.get(CLASS_ARGUMENT_INDEX); - if (classArgument.isConstant()) { + ValueNode nonNullArgument = arguments.get(NONNULL_ARGUMENT_INDEX); + if (classArgument.isConstant() && nonNullArgument.isConstant()) { ValueNode objectArgument = arguments.get(OBJECT_ARGUMENT_INDEX); ValueNode conditionArgument = arguments.get(CONDITION_ARGUMENT_INDEX); Class c = (Class) classArgument.asConstant().asObject(); @@ -58,8 +60,9 @@ return objectArgument; } ResolvedJavaType lookupJavaType = tool.getMetaAccess().lookupJavaType(c); + 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, StampFactory.declaredNonNull(lookupJavaType), valueAnchorNode)); + UnsafeCastNode piCast = graph().unique(new UnsafeCastNode(objectArgument, stamp, valueAnchorNode)); this.replaceAtUsages(piCast); return valueAnchorNode; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Sun Mar 30 16:08:33 2014 +0200 @@ -71,7 +71,7 @@ public static native void bailout(String reason); @MacroSubstitution(macro = UnsafeTypeCastMacroNode.class, isStatic = true) - public static native Object unsafeCast(Object value, Class clazz, boolean condition); + public static native Object unsafeCast(Object value, Class clazz, boolean condition, boolean nonNull); @MethodSubstitution private static Class getUnsafeFrameType() { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetImplSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetImplSubstitutions.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013, 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.truffle.substitutions; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.truffle.*; +import com.oracle.graal.truffle.nodes.asserts.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; + +@ClassSubstitution(OptimizedCallTargetImpl.class) +public class OptimizedCallTargetImplSubstitutions { + + @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) + public static native Object callHelper(OptimizedCallTarget target, PackedFrame caller, Arguments args); + + @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) + public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args); + + @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) + public static native Object compiledCodeInvalidated(OptimizedCallTarget target, PackedFrame caller, Arguments args); +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java Sun Mar 30 16:08:33 2014 +0200 @@ -23,9 +23,7 @@ package com.oracle.graal.truffle.substitutions; import com.oracle.graal.api.replacements.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.truffle.*; -import com.oracle.graal.truffle.nodes.asserts.*; import com.oracle.graal.truffle.nodes.frame.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; @@ -33,15 +31,6 @@ @ClassSubstitution(OptimizedCallTarget.class) public class OptimizedCallTargetSubstitutions { - @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) - public static native Object callHelper(OptimizedCallTarget target, PackedFrame caller, Arguments args); - - @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) - public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args); - - @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) - public static native Object compiledCodeInvalidated(OptimizedCallTarget target, PackedFrame caller, Arguments args); - @MethodSubstitution private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { return NewFrameNode.allocate(FrameWithoutBoxing.class, descriptor, caller, args); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java Wed Mar 19 11:43:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013, 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.truffle.substitutions; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.nodes.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Deoptimize on creation of a new UnexpectedResultException instance. - */ -@ClassSubstitution(UnexpectedResultException.class) -public class UnexpectedResultExceptionSubstitutions { - - @SuppressWarnings("unused") - @MethodSubstitution(value = "") - public static void init(Object result) { - DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode); - } -} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.virtual.phases.ea; +import static com.oracle.graal.debug.Debug.*; + import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; @@ -59,8 +61,7 @@ public boolean runAnalysis(final StructuredGraph graph, final PhaseContextT context) { boolean changed = false; for (int iteration = 0; iteration < maxIterations; iteration++) { - - try (Scope s = Debug.scope("iteration " + iteration)) { + try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) { SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph, false); Closure closure = createEffectsClosure(context, schedule); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.virtual.phases.ea; +import static com.oracle.graal.debug.Debug.*; import static com.oracle.graal.phases.GraalOptions.*; import java.util.*; @@ -41,8 +42,8 @@ } public static final void trace(String format, Object... obj) { - if (TraceEscapeAnalysis.getValue()) { - Debug.log(format, obj); + if (TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { + Debug.logv(format, obj); } } @@ -54,7 +55,7 @@ private void runIterations(final StructuredGraph graph, final boolean simple, final HighTierContext context) { for (int iteration = 0; iteration < EscapeAnalysisIterations.getValue(); iteration++) { - try (Scope s = Debug.scope("iteration " + iteration)) { + try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) { boolean progress = false; PartialEscapePhase ea = new PartialEscapePhase(false, canonicalizer); boolean eaResult = ea.runAnalysis(graph, context); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Sun Mar 30 16:08:33 2014 +0200 @@ -173,7 +173,7 @@ } } for (PhiNode phi : merge.phis()) { - if (phi.kind() == Kind.Object) { + if (phi.getKind() == Kind.Object) { for (Map.Entry entry : states.get(0).readCache.entrySet()) { if (entry.getKey().object == phi.valueAt(0)) { mergeReadCachePhi(phi, entry.getKey().identity, states); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Sun Mar 30 16:08:33 2014 +0200 @@ -132,75 +132,78 @@ } private void processNodeWithState(NodeWithState nodeWithState, final BlockT state, final GraphEffectList effects) { - FrameState frameState = nodeWithState.getState(); - if (frameState != null) { - if (frameState.usages().count() > 1) { - nodeWithState.asNode().replaceFirstInput(frameState, frameState.copyWithInputs()); - frameState = nodeWithState.getState(); - } - final Set virtual = new ArraySet<>(); - frameState.applyToNonVirtual(new NodeClosure() { + for (Node input : nodeWithState.asNode().inputs()) { + if (input instanceof FrameState) { + FrameState frameState = (FrameState) input; + if (frameState.usages().count() > 1) { + FrameState copy = (FrameState) frameState.copyWithInputs(); + nodeWithState.asNode().replaceFirstInput(frameState, copy); + frameState = copy; + } + final Set virtual = new ArraySet<>(); + frameState.applyToNonVirtual(new NodeClosure() { - @Override - public void apply(Node usage, ValueNode value) { - ObjectState valueObj = getObjectState(state, value); - if (valueObj != null) { - virtual.add(valueObj); - effects.replaceFirstInput(usage, value, valueObj.virtual); - } else if (value instanceof VirtualObjectNode) { - ObjectState virtualObj = null; - for (ObjectState obj : state.getStates()) { - if (value == obj.virtual) { - virtualObj = obj; - break; + @Override + public void apply(Node usage, ValueNode value) { + ObjectState valueObj = getObjectState(state, value); + if (valueObj != null) { + virtual.add(valueObj); + effects.replaceFirstInput(usage, value, valueObj.virtual); + } else if (value instanceof VirtualObjectNode) { + ObjectState virtualObj = null; + for (ObjectState obj : state.getStates()) { + if (value == obj.virtual) { + virtualObj = obj; + break; + } + } + if (virtualObj != null) { + virtual.add(virtualObj); } } - if (virtualObj != null) { - virtual.add(virtualObj); - } + } + }); + for (ObjectState obj : state.getStates()) { + if (obj.isVirtual() && obj.hasLocks()) { + virtual.add(obj); } } - }); - for (ObjectState obj : state.getStates()) { - if (obj.isVirtual() && obj.hasLocks()) { - virtual.add(obj); - } - } - ArrayDeque queue = new ArrayDeque<>(virtual); - while (!queue.isEmpty()) { - ObjectState obj = queue.removeLast(); - if (obj.isVirtual()) { - for (ValueNode field : obj.getEntries()) { - if (field instanceof VirtualObjectNode) { - ObjectState fieldObj = state.getObjectState((VirtualObjectNode) field); - if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) { - virtual.add(fieldObj); - queue.addLast(fieldObj); + ArrayDeque queue = new ArrayDeque<>(virtual); + while (!queue.isEmpty()) { + ObjectState obj = queue.removeLast(); + if (obj.isVirtual()) { + for (ValueNode field : obj.getEntries()) { + if (field instanceof VirtualObjectNode) { + ObjectState fieldObj = state.getObjectState((VirtualObjectNode) field); + if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) { + virtual.add(fieldObj); + queue.addLast(fieldObj); + } } } } } - } - for (ObjectState obj : virtual) { - EscapeObjectState v; - if (obj.isVirtual()) { - ValueNode[] fieldState = obj.getEntries().clone(); - for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = getObjectState(state, fieldState[i]); - if (valueObj != null) { - if (valueObj.isVirtual()) { - fieldState[i] = valueObj.virtual; - } else { - fieldState[i] = valueObj.getMaterializedValue(); + for (ObjectState obj : virtual) { + EscapeObjectState v; + if (obj.isVirtual()) { + ValueNode[] fieldState = obj.getEntries().clone(); + for (int i = 0; i < fieldState.length; i++) { + ObjectState valueObj = getObjectState(state, fieldState[i]); + if (valueObj != null) { + if (valueObj.isVirtual()) { + fieldState[i] = valueObj.virtual; + } else { + fieldState[i] = valueObj.getMaterializedValue(); + } } } + v = new VirtualObjectState(obj.virtual, fieldState); + } else { + v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue()); } - v = new VirtualObjectState(obj.virtual, fieldState); - } else { - v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue()); + effects.addVirtualMapping(frameState, v); } - effects.addVirtualMapping(frameState, v); } } } @@ -411,7 +414,7 @@ ValueNode[] entries = objStates[i].getEntries(); int valueIndex = 0; while (valueIndex < values.length) { - Kind otherKind = entries[valueIndex].kind(); + Kind otherKind = entries[valueIndex].getKind(); Kind entryKind = object.entryKind(valueIndex); if (entryKind == Kind.Int && (otherKind == Kind.Long || otherKind == Kind.Double)) { if (twoSlotKinds == null) { @@ -437,7 +440,7 @@ assert valueIndex < object.entryCount() - 1 && object.entryKind(valueIndex) == Kind.Int && object.entryKind(valueIndex + 1) == Kind.Int; for (int i = 0; i < objStates.length; i++) { ValueNode value = objStates[i].getEntry(valueIndex); - Kind valueKind = value.kind(); + Kind valueKind = value.getKind(); if (valueKind != twoSlotKinds[valueIndex]) { ValueNode nextValue = objStates[i].getEntry(valueIndex + 1); if (value.isConstant() && value.asConstant().equals(Constant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(Constant.INT_0)) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Sun Mar 30 16:08:33 2014 +0200 @@ -94,6 +94,9 @@ ReadCacheEntry identifier = new ReadCacheEntry(object, read.location()); ValueNode cachedValue = state.getCacheEntry(identifier); if (cachedValue != null) { + if (read.getGuard() != null && !(read.getGuard() instanceof FixedNode)) { + effects.addFixedNodeBefore(new ValueAnchorNode((ValueNode) read.getGuard()), read); + } effects.replaceAtUsages(read, cachedValue); addScalarAlias(read, cachedValue); deleted = true; @@ -241,7 +244,7 @@ } } for (PhiNode phi : merge.phis()) { - if (phi.kind() == Kind.Object) { + if (phi.getKind() == Kind.Object) { for (Map.Entry, ValueNode> entry : states.get(0).readCache.entrySet()) { if (entry.getKey().object == phi.valueAt(0)) { mergeReadCachePhi(phi, entry.getKey(), states); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Sun Mar 30 16:08:33 2014 +0200 @@ -109,8 +109,8 @@ } public static void trace(String format, Object... obj) { - if (TraceEscapeAnalysis.getValue()) { - Debug.log(format, obj); + if (TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { + Debug.logv(format, obj); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Sun Mar 30 16:08:33 2014 +0200 @@ -93,11 +93,11 @@ ObjectState valueState = closure.getObjectState(state, value); if (valueState == null) { newValue = getReplacedValue(value); - assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).kind() == newValue.kind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); + assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); } else { if (valueState.getState() != EscapeState.Virtual) { newValue = valueState.getMaterializedValue(); - assert newValue.kind() == Kind.Object; + assert newValue.getKind() == Kind.Object; } else { newValue = valueState.getVirtualObject(); } @@ -108,7 +108,7 @@ } private static boolean isObjectEntry(ValueNode value) { - return value.kind() == Kind.Object || value instanceof VirtualObjectNode; + return value.getKind() == Kind.Object || value instanceof VirtualObjectNode; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -37,12 +37,12 @@ public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable { public static WordCastNode wordToObject(ValueNode input, Kind wordKind) { - assert input.kind() == wordKind; + assert input.getKind() == wordKind; return new WordCastNode(StampFactory.object(), input); } public static WordCastNode objectToWord(ValueNode input, Kind wordKind) { - assert input.kind() == Kind.Object; + assert input.getKind() == Kind.Object; return new WordCastNode(StampFactory.forKind(wordKind), input); } @@ -67,12 +67,12 @@ } @Override - public void generate(LIRGeneratorTool generator) { - assert kind() != input.kind(); - assert generator.target().getSizeInBytes(kind()) == generator.target().getSizeInBytes(input.kind()); + public void generate(NodeLIRGeneratorTool generator) { + assert getKind() != input.getKind(); + assert generator.getLIRGeneratorTool().target().getSizeInBytes(getKind()) == generator.getLIRGeneratorTool().target().getSizeInBytes(input.getKind()); - AllocatableValue result = generator.newVariable(kind()); - generator.emitMove(result, generator.operand(input)); + AllocatableValue result = generator.getLIRGeneratorTool().newVariable(getKind()); + generator.getLIRGeneratorTool().emitMove(result, generator.operand(input)); generator.setResult(this, result); } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Sun Mar 30 16:08:33 2014 +0200 @@ -116,7 +116,7 @@ * Remove casts between word types (which by now no longer have kind Object). */ protected void rewriteCheckCast(StructuredGraph graph, CheckCastNode node) { - if (node.kind() == wordKind) { + if (node.getKind() == wordKind) { node.replaceAtUsages(node.object()); graph.removeFixed(node); } @@ -173,7 +173,7 @@ } if (!callTargetNode.isStatic()) { - assert callTargetNode.receiver().kind() == wordKind : "changeToWord() missed the receiver"; + assert callTargetNode.receiver().getKind() == wordKind : "changeToWord() missed the receiver"; targetMethod = wordImplType.resolveMethod(targetMethod); } Operation operation = targetMethod.getAnnotation(Word.Operation.class); @@ -214,7 +214,7 @@ } else { location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2)); } - replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, BarrierType.NONE, false)); + replace(invoke, readOp(graph, arguments.get(0), invoke, location, StampFactory.forKind(readKind.getStackKind()), BarrierType.NONE, false)); break; } case READ_HEAP: { @@ -222,7 +222,8 @@ Kind readKind = asKind(callTargetNode.returnType()); LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION); BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject(); - replace(invoke, readOp(graph, arguments.get(0), invoke, location, readKind, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true)); + boolean compressible = arguments.get(3).asConstant().asInt() != 0; + replace(invoke, readOp(graph, arguments.get(0), invoke, location, StampFactory.forKind(readKind.getStackKind()), barrierType, compressible)); break; } case WRITE: @@ -295,16 +296,16 @@ } private static ValueNode convert(StructuredGraph graph, ValueNode value, Kind toKind, boolean unsigned) { - if (value.kind() == toKind) { + if (value.getKind() == toKind) { return value; } if (toKind == Kind.Int) { - assert value.kind() == Kind.Long; + assert value.getKind() == Kind.Long; return graph.unique(new NarrowNode(value, 32)); } else { assert toKind == Kind.Long; - assert value.kind().getStackKind() == Kind.Int; + assert value.getKind().getStackKind() == Kind.Int; if (unsigned) { return graph.unique(new ZeroExtendNode(value, 64)); } else { @@ -328,7 +329,7 @@ } private ValueNode comparisonOp(StructuredGraph graph, Condition condition, ValueNode left, ValueNode right) { - assert left.kind() == wordKind && right.kind() == wordKind; + assert left.getKind() == wordKind && right.getKind() == wordKind; // mirroring gets the condition into canonical form boolean mirror = condition.canonicalMirror(); @@ -369,8 +370,8 @@ return IndexedLocationNode.create(locationIdentity, readKind, 0, fromSigned(graph, offset), graph, 1); } - protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Kind readKind, BarrierType barrierType, boolean compressible) { - ReadNode read = graph.add(new ReadNode(base, location, StampFactory.forKind(readKind.getStackKind()), barrierType, compressible)); + protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Stamp stamp, BarrierType barrierType, boolean compressible) { + ReadNode read = graph.add(new ReadNode(base, location, stamp, barrierType, compressible)); graph.addBeforeFixed(invoke.asNode(), read); /* * The read must not float outside its block otherwise it may float above an explicit zero diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -71,6 +71,7 @@ public void testImplicitCast0() { ImplicitCast0Node node = ImplicitCast0NodeFactory.create(null); TestRootNode root = new TestRootNode<>(node); + root.adoptChildren(); Assert.assertEquals("2", root.getNode().executeEvaluated(null, "2")); Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1)); Assert.assertEquals("1", root.getNode().executeEvaluated(null, "1")); @@ -106,6 +107,7 @@ public void testImplicitCast1() { ImplicitCast1Node node = ImplicitCast1NodeFactory.create(null); TestRootNode root = new TestRootNode<>(node); + root.adoptChildren(); Assert.assertEquals("2", root.getNode().executeEvaluated(null, "2")); Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1)); Assert.assertEquals("1", root.getNode().executeEvaluated(null, "1")); @@ -146,6 +148,7 @@ public void testImplicitCast2() { ImplicitCast2Node node = ImplicitCast2NodeFactory.create(null, null); TestRootNode root = new TestRootNode<>(node); + root.adoptChildren(); Assert.assertEquals("42", root.getNode().executeEvaluated(null, "4", "2")); Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1, 1)); Assert.assertEquals("42", root.getNode().executeEvaluated(null, "4", "2")); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -64,7 +64,7 @@ TestRootNode node = TestHelper.createRoot(Node1Factory.getInstance()); assertEquals("(int,boolean)", executeWith(node, 42, false)); assertEquals("(int,int)", executeWith(node, 42, 42)); - assertEquals(NodeCost.NONE, node.getNode().getCost()); + assertEquals(NodeCost.POLYMORPHIC, node.getNode().getCost()); assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); } @@ -75,7 +75,7 @@ assertEquals("(int,boolean)", executeWith(node, 42, false)); assertEquals("(boolean,boolean)", executeWith(node, true, false)); assertEquals("(int,int)", executeWith(node, 42, 42)); - assertEquals(NodeCost.NONE, node.getNode().getCost()); + assertEquals(NodeCost.POLYMORPHIC, node.getNode().getCost()); assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java Sun Mar 30 16:08:33 2014 +0200 @@ -42,7 +42,7 @@ assertEquals(21, executeWith(node, false, false)); assertEquals(42, executeWith(node, 21, 21)); assertEquals("(boolean,int)", executeWith(node, false, 42)); - assertEquals(NodeCost.NONE, node.getNode().getCost()); + assertEquals(NodeCost.POLYMORPHIC, node.getNode().getCost()); } @SuppressWarnings("unused") diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Sun Mar 30 16:08:33 2014 +0200 @@ -76,11 +76,15 @@ } static TestRootNode createRoot(NodeFactory factory, Object... constants) { - return new TestRootNode<>(createNode(factory, constants)); + TestRootNode rootNode = new TestRootNode<>(createNode(factory, constants)); + rootNode.adoptChildren(); + return rootNode; } static TestRootNode createGenericRoot(NodeFactory factory, Object... constants) { - return new TestRootNode<>(createGenericNode(factory, constants)); + TestRootNode rootNode = new TestRootNode<>(createGenericNode(factory, constants)); + rootNode.adoptChildren(); + return rootNode; } static CallTarget createCallTarget(ValueNode node) { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -100,7 +100,7 @@ public TestRootNode(E node) { super(null); - this.node = adoptChild(node); + this.node = node; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -61,7 +61,7 @@ Assert.assertEquals(42, result); } - class TestArguments extends Arguments { + private static class TestArguments extends Arguments { final int[] values; @@ -70,13 +70,13 @@ } } - class TestRootNode extends RootNode { + private static class TestRootNode extends RootNode { - @Children private TestArgumentNode[] children; + @Children private final TestArgumentNode[] children; TestRootNode(TestArgumentNode[] children) { super(null); - this.children = adoptChildren(children); + this.children = children; } @Override @@ -89,7 +89,7 @@ } } - class TestArgumentNode extends Node { + private static class TestArgumentNode extends Node { private final int index; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -61,13 +61,13 @@ TestChildNode leftChild = new TestChildNode(); TestChildNode rightChild = new TestChildNode(); TestRootNode rootNode = new TestRootNode(leftChild, rightChild); + CallTarget target = runtime.createCallTarget(rootNode); Assert.assertEquals(rootNode, leftChild.getParent()); Assert.assertEquals(rootNode, rightChild.getParent()); Iterator iterator = rootNode.getChildren().iterator(); Assert.assertEquals(leftChild, iterator.next()); Assert.assertEquals(rightChild, iterator.next()); Assert.assertFalse(iterator.hasNext()); - CallTarget target = runtime.createCallTarget(rootNode); Object result = target.call(); Assert.assertEquals(42, result); } @@ -79,8 +79,8 @@ public TestRootNode(TestChildNode left, TestChildNode right) { super(null); - this.left = adoptChild(left); - this.right = adoptChild(right); + this.left = left; + this.right = right; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -55,13 +55,13 @@ TestChildNode firstChild = new TestChildNode(); TestChildNode secondChild = new TestChildNode(); TestRootNode rootNode = new TestRootNode(new TestChildNode[]{firstChild, secondChild}); + CallTarget target = runtime.createCallTarget(rootNode); Assert.assertEquals(rootNode, firstChild.getParent()); Assert.assertEquals(rootNode, secondChild.getParent()); Iterator iterator = rootNode.getChildren().iterator(); Assert.assertEquals(firstChild, iterator.next()); Assert.assertEquals(secondChild, iterator.next()); Assert.assertFalse(iterator.hasNext()); - CallTarget target = runtime.createCallTarget(rootNode); Object result = target.call(); Assert.assertEquals(42, result); } @@ -72,7 +72,7 @@ public TestRootNode(TestChildNode[] children) { super(null); - this.children = adoptChildren(children); + this.children = children; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -60,13 +60,13 @@ Assert.assertEquals(42, result); } - class TestRootNode extends RootNode { + private static class TestRootNode extends RootNode { - @Children TestChildNode[] children; + @Children private final TestChildNode[] children; public TestRootNode(TestChildNode[] children) { super(null); - this.children = adoptChildren(children); + this.children = children; } @Override @@ -79,7 +79,7 @@ } } - class TestChildNode extends Node { + private static class TestChildNode extends Node { private final int value; diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -64,8 +64,8 @@ public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) { super(null, descriptor); - this.left = adoptChild(left); - this.right = adoptChild(right); + this.left = left; + this.right = right; } @Override @@ -108,7 +108,7 @@ IntAssignLocal(FrameSlot slot, TestChildNode value) { super(slot); - this.value = adoptChild(value); + this.value = value; } @Override @@ -130,7 +130,7 @@ ObjectAssignLocal(FrameSlot slot, TestChildNode value) { super(slot); - this.value = adoptChild(value); + this.value = value; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -88,8 +88,8 @@ public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) { super(null, descriptor); - this.left = adoptChild(left); - this.right = adoptChild(right); + this.left = left; + this.right = right; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -59,13 +59,13 @@ UnresolvedNode leftChild = new UnresolvedNode("20"); UnresolvedNode rightChild = new UnresolvedNode("22"); TestRootNode rootNode = new TestRootNode(new ValueNode[]{leftChild, rightChild}); + CallTarget target = runtime.createCallTarget(rootNode); assertEquals(rootNode, leftChild.getParent()); assertEquals(rootNode, rightChild.getParent()); Iterator iterator = rootNode.getChildren().iterator(); Assert.assertEquals(leftChild, iterator.next()); Assert.assertEquals(rightChild, iterator.next()); Assert.assertFalse(iterator.hasNext()); - CallTarget target = runtime.createCallTarget(rootNode); Object result = target.call(); assertEquals(42, result); assertEquals(42, target.call()); @@ -85,7 +85,7 @@ public TestRootNode(ValueNode[] children) { super(null); - this.children = adoptChildren(children); + this.children = children; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -63,8 +63,8 @@ public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) { super(null, descriptor); - this.left = adoptChild(left); - this.right = adoptChild(right); + this.left = left; + this.right = right; } @Override @@ -115,7 +115,7 @@ IntAssignLocal(FrameSlot slot, TestChildNode value) { super(slot); - this.value = adoptChild(value); + this.value = value; } @Override @@ -137,7 +137,7 @@ ObjectAssignLocal(FrameSlot slot, TestChildNode value) { super(slot); - this.value = adoptChild(value); + this.value = value; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2014, 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.truffle.api.test; + +import static org.junit.Assert.*; + +import java.io.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Test node rewriting in a tree shared across multiple threads (run with -ea). + */ +public class ThreadSafetyTest { + + @Test + public void test() throws InterruptedException { + TruffleRuntime runtime = Truffle.getRuntime(); + TestRootNode rootNode1 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new ConstNode(42))))))); + final CallTarget target1 = runtime.createCallTarget(rootNode1); + NodeUtil.verify(rootNode1); + + RecursiveCallNode callNode = new RecursiveCallNode(new ConstNode(42)); + TestRootNode rootNode2 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(callNode)))))); + final CallTarget target2 = runtime.createCallTarget(rootNode2); + callNode.setCallNode(runtime.createCallNode(target2)); + NodeUtil.verify(rootNode2); + + testTarget(target1, 47, 1_000_000); + testTarget(target2, 72, 1_000_000); + } + + private static void testTarget(final CallTarget target, final int expectedResult, final int numberOfIterations) throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(20); + final AtomicInteger ai = new AtomicInteger(); + for (int i = 0; i < numberOfIterations; i++) { + executorService.submit(new Runnable() { + public void run() { + try { + Object result = target.call(new TestArguments(5)); + assertEquals(expectedResult, result); + ai.incrementAndGet(); + } catch (Throwable t) { + PrintStream out = System.out; + out.println(t); + } + } + }); + } + executorService.shutdown(); + executorService.awaitTermination(90, TimeUnit.SECONDS); + assertTrue("test did not terminate", executorService.isTerminated()); + assertEquals(numberOfIterations, ai.get()); + } + + static class TestArguments extends Arguments { + final int arg; + + public TestArguments(int arg) { + this.arg = arg; + } + } + + static class TestRootNode extends RootNode { + + @Child private ValueNode child; + + public TestRootNode(ValueNode child) { + super(null); + this.child = child; + } + + @Override + public Object execute(VirtualFrame frame) { + return child.execute(frame); + } + } + + abstract static class ValueNode extends Node { + + public ValueNode() { + super(null); + } + + abstract int execute(VirtualFrame frame); + } + + static class RewritingNode extends ValueNode { + + @Child private ValueNode child; + private final Random random; + + public RewritingNode(ValueNode child) { + this(child, new Random()); + } + + public RewritingNode(ValueNode child, Random random) { + this.child = child; + this.random = random; + } + + @Override + int execute(VirtualFrame frame) { + boolean replace = random.nextBoolean(); + if (replace) { + ValueNode newNode = this.replace(new OtherRewritingNode(child, random)); + return newNode.execute(frame); + } + return 1 + child.execute(frame); + } + } + + static class OtherRewritingNode extends ValueNode { + + @Child private ValueNode child; + private final Random random; + + public OtherRewritingNode(ValueNode child, Random random) { + this.child = child; + this.random = random; + } + + @Override + int execute(VirtualFrame frame) { + boolean replace = random.nextBoolean(); + if (replace) { + ValueNode newNode = this.replace(new RewritingNode(child, random)); + return newNode.execute(frame); + } + return 1 + child.execute(frame); + } + } + + static class ConstNode extends ValueNode { + + private final int value; + + ConstNode(int value) { + this.value = value; + } + + @Override + int execute(VirtualFrame frame) { + return value; + } + } + + static class RecursiveCallNode extends ValueNode { + @Child CallNode callNode; + @Child private ValueNode valueNode; + + RecursiveCallNode(ValueNode value) { + this.valueNode = value; + } + + @Override + int execute(VirtualFrame frame) { + int arg = frame.getArguments(TestArguments.class).arg; + if (arg > 0) { + return (int) callNode.call(frame.pack(), new TestArguments(arg - 1)); + } else { + return valueNode.execute(frame); + } + } + + void setCallNode(CallNode callNode) { + this.callNode = insert(callNode); + } + } +} diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderDeserializerTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderDeserializerTest.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/PostOrderDeserializerTest.java Sun Mar 30 16:08:33 2014 +0200 @@ -151,6 +151,8 @@ return; } + expectedAst.adoptChildren(); + Assert.assertNotNull(actualAst); // fields are asserted using the corresponding equals implementation Assert.assertEquals(expectedAst, actualAst); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestNodes.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestNodes.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/serial/TestNodes.java Sun Mar 30 16:08:33 2014 +0200 @@ -84,7 +84,7 @@ @Child Node child; public NodeWithOneChild(Node child) { - this.child = adoptChild(child); + this.child = child; } } @@ -95,8 +95,8 @@ @Child Node child2; public NodeWithTwoChilds(Node child1, Node child2) { - this.child1 = adoptChild(child1); - this.child2 = adoptChild(child2); + this.child1 = child1; + this.child2 = child2; } } @@ -108,9 +108,9 @@ @Child Node child3; public NodeWithThreeChilds(Node child1, Node child2, Node child3) { - this.child1 = adoptChild(child1); - this.child2 = adoptChild(child2); - this.child3 = adoptChild(child3); + this.child1 = child1; + this.child2 = child2; + this.child3 = child3; } } @@ -120,7 +120,7 @@ @Children private final Node[] childNodes; NodeWithArray(Node[] children) { - this.childNodes = adoptChildren(children); + this.childNodes = children; } Node[] getChildNodes() { @@ -134,8 +134,8 @@ @Children private final Node[] childNodes2; NodeWithTwoArray(Node[] childs1, Node[] childs2) { - this.childNodes1 = adoptChildren(childs1); - this.childNodes2 = adoptChildren(childs2); + this.childNodes1 = childs1; + this.childNodes2 = childs2; } Node[] getChildNodes1() { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Sun Mar 30 16:08:33 2014 +0200 @@ -76,7 +76,7 @@ /** * Returns a boolean value indicating whether the method is executed in the interpreter. - * + * * @return {@code true} when executed in the interpreter, {@code false} in compiled code. */ public static boolean inInterpreter() { @@ -86,7 +86,7 @@ /** * Directive for the compiler that the given runnable should only be executed in the interpreter * and ignored in the compiled code. - * + * * @param runnable the closure that should only be executed in the interpreter */ public static void interpreterOnly(Runnable runnable) { @@ -96,7 +96,7 @@ /** * Directive for the compiler that the given callable should only be executed in the * interpreter. - * + * * @param callable the closure that should only be executed in the interpreter * @return the result of executing the closure in the interpreter and null in the compiled code * @throws Exception If the closure throws an exception when executed in the interpreter. @@ -109,30 +109,30 @@ * Injects a probability for the given condition into the probability information of the * immediately succeeding branch instruction for the condition. The probability must be a value * between 0.0 and 1.0 (inclusive). The condition should not be a combined condition. - * + * * Example usage immediately before an if statement (it specifies that the likelihood for a to * be greater than b is 90%): - * + * * * if (injectBranchProbability(0.9, a > b)) { * // ... * } * - * + * * Example usage for a combined condition (it specifies that the likelihood for a to be greater * than b is 90% and under the assumption that this is true, the likelihood for a being 0 is * 10%): - * + * * * if (injectBranchProbability(0.9, a > b) && injectBranchProbability(0.1, a == 0)) { * // ... * } * - * + * * There are predefined constants for commonly used probabilities (see * {@link #LIKELY_PROBABILITY} , {@link #UNLIKELY_PROBABILITY}, {@link #SLOWPATH_PROBABILITY}, * {@link #FASTPATH_PROBABILITY} ). - * + * * @param probability the probability value between 0.0 and 1.0 that should be injected */ public static boolean injectBranchProbability(double probability, boolean condition) { @@ -142,7 +142,7 @@ /** * Bails out of a compilation (e.g., for guest language features that should never be compiled). - * + * * @param reason the reason for the bailout */ public static void bailout(String reason) { @@ -161,21 +161,37 @@ * Casts the given value to the value of the given type without any checks. The class must * evaluate to a constant. The condition parameter gives a hint to the compiler under which * circumstances this cast can be moved to an earlier location in the program. - * + * * @param value the value that is known to have the specified type * @param type the specified new type of the value * @param condition the condition that makes this cast safe also at an earlier location of the * program * @return the value to be casted to the new type */ + public static T unsafeCast(Object value, Class type, boolean condition) { + return unsafeCast(value, type, condition, false); + } + + /** + * Casts the given value to the value of the given type without any checks. The class must + * evaluate to a constant. The condition parameter gives a hint to the compiler under which + * circumstances this cast can be moved to an earlier location in the program. + * + * @param value the value that is known to have the specified type + * @param type the specified new type of the value + * @param condition the condition that makes this cast safe also at an earlier location of the + * program + * @param nonNull whether value is known to never be null + * @return the value to be casted to the new type + */ @SuppressWarnings("unchecked") - public static T unsafeCast(Object value, Class type, boolean condition) { + public static T unsafeCast(Object value, Class type, boolean condition, boolean nonNull) { return (T) value; } /** * Asserts that this value is not null and retrieved from a call to Frame.materialize. - * + * * @param value the value that is known to have been obtained via Frame.materialize * @return the value to be casted to the new type */ @@ -192,7 +208,7 @@ * the compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -210,7 +226,7 @@ * compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -228,7 +244,7 @@ * compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -246,7 +262,7 @@ * compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -264,7 +280,7 @@ * compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -282,7 +298,7 @@ * compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -300,7 +316,7 @@ * compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -318,7 +334,7 @@ * the compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -334,7 +350,7 @@ /** * Write a boolean value within an object. The location identity gives a hint to the compiler * for improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -348,7 +364,7 @@ /** * Write a byte value within an object. The location identity gives a hint to the compiler for * improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -362,7 +378,7 @@ /** * Write a short value within an object. The location identity gives a hint to the compiler for * improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -376,7 +392,7 @@ /** * Write an int value within an object. The location identity gives a hint to the compiler for * improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -390,7 +406,7 @@ /** * Write a long value within an object. The location identity gives a hint to the compiler for * improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -404,7 +420,7 @@ /** * Write a float value within an object. The location identity gives a hint to the compiler for * improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -418,7 +434,7 @@ /** * Write a double value within an object. The location identity gives a hint to the compiler for * improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -432,7 +448,7 @@ /** * Write an Object value within an object. The location identity gives a hint to the compiler * for improved global value numbering. - * + * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes * @param value the value to be written @@ -448,7 +464,7 @@ * to the compiler under which circumstances this access can be moved to an earlier location in * the program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -466,7 +482,7 @@ * the compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -484,7 +500,7 @@ * to the compiler under which circumstances this access can be moved to an earlier location in * the program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -502,7 +518,7 @@ * the compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -520,7 +536,7 @@ * the compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -538,7 +554,7 @@ * to the compiler under which circumstances this access can be moved to an earlier location in * the program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -556,7 +572,7 @@ * to the compiler under which circumstances this access can be moved to an earlier location in * the program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the @@ -574,7 +590,7 @@ * to the compiler under which circumstances this access can be moved to an earlier location in * the program. The location identity gives a hint to the compiler for improved global value * numbering. - * + * * @param receiver the object that is accessed * @param offset the offset at which to access the object in bytes * @param condition the condition that makes this access safe also at an earlier location in the diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java Sun Mar 30 16:08:33 2014 +0200 @@ -37,6 +37,7 @@ public RootCallTarget(RootNode function) { this.rootNode = function; this.rootNode.setCallTarget(this); + this.rootNode.adoptChildren(); } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Sun Mar 30 16:08:33 2014 +0200 @@ -27,6 +27,7 @@ import java.io.*; import java.lang.annotation.*; import java.util.*; +import java.util.concurrent.*; import com.oracle.truffle.api.*; @@ -133,11 +134,36 @@ * @param newChildren the array of new children whose parent should be updated * @return the array of new children */ - protected final T[] adoptChildren(T[] newChildren) { - if (newChildren != null) { - for (T n : newChildren) { - adoptChild(n); - } + @SuppressWarnings("static-method") + @Deprecated + protected final T[] adoptChildren(final T[] newChildren) { + return newChildren; + } + + /** + * Method that updates the link to the parent in the specified new child node to this node. + * + * @param newChild the new child whose parent should be updated + * @return the new child + */ + @SuppressWarnings("static-method") + @Deprecated + protected final T adoptChild(final T newChild) { + return newChild; + } + + /** + * Method that updates the link to the parent in the array of specified new child nodes to this + * node. + * + * @param newChildren the array of new children whose parent should be updated + * @return the array of new children + */ + protected final T[] insert(final T[] newChildren) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + assert newChildren != null; + for (Node newChild : newChildren) { + adoptHelper(newChild); } return newChildren; } @@ -148,14 +174,52 @@ * @param newChild the new child whose parent should be updated * @return the new child */ - protected final T adoptChild(T newChild) { - if (newChild != null) { - if (newChild == this) { - throw new IllegalStateException("The parent of a node can never be the node itself."); + protected final T insert(final T newChild) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + assert newChild != null; + adoptHelper(newChild); + return newChild; + } + + public final void adoptChildren() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + adoptHelper(); + } + + private void adoptHelper(final Node newChild) { + assert newChild != null; + if (newChild == this) { + throw new IllegalStateException("The parent of a node can never be the node itself."); + } + newChild.parent = this; + newChild.adoptHelper(); + } + + private void adoptHelper() { + Iterable children = this.getChildren(); + for (Node child : children) { + if (child != null && child.getParent() != this) { + this.adoptHelper(child); } - ((Node) newChild).parent = this; + } + } + + private void adoptUnadoptedHelper(final Node newChild) { + assert newChild != null; + if (newChild == this) { + throw new IllegalStateException("The parent of a node can never be the node itself."); } - return newChild; + newChild.parent = this; + newChild.adoptUnadoptedHelper(); + } + + private void adoptUnadoptedHelper() { + Iterable children = this.getChildren(); + for (Node child : children) { + if (child != null && child.getParent() == null) { + this.adoptUnadoptedHelper(child); + } + } } /** @@ -186,54 +250,17 @@ * @param reason a description of the reason for the replacement * @return the new node */ - public final T replace(T newNode, CharSequence reason) { + public final T replace(final T newNode, final CharSequence reason) { CompilerDirectives.transferToInterpreterAndInvalidate(); - if (this.getParent() == null) { - throw new IllegalStateException("This node cannot be replaced, because it does not yet have a parent."); - } - if (sourceSection != null && newNode.getSourceSection() == null) { - // Pass on the source section to the new node. - newNode.assignSourceSection(sourceSection); - } - onReplace(newNode, reason); - ((Node) newNode).parent = this.parent; - if (!NodeUtil.replaceChild(this.parent, this, newNode)) { - fixupTree(); - } - reportReplace(this, newNode, reason); + atomic(new Runnable() { + public void run() { + replaceHelper(newNode, reason); + } + }); return newNode; } /** - * Rewrite has failed; the tree is likely inconsistent, so fix any stale parent references. - * - * This is a rather expensive operation but rare to occur. - */ - private void fixupTree() { - Node rootNode = getRootNode(); - if (rootNode == null) { - throw new UnsupportedOperationException("Tree does not have a root node."); - } - int fixCount = rootNode.fixupChildren(); - assert fixCount != 0 : "sanity check failed: missing @Child[ren] or adoptChild?"; - // if nothing had to be fixed, rewrite failed due to node not being a proper child. - } - - private int fixupChildren() { - int fixCount = 0; - for (Node child : getChildren()) { - if (child != null) { - if (child.parent != this) { - child.parent = this; - fixCount++; - } - fixCount += child.fixupChildren(); - } - } - return fixCount; - } - - /** * Replaces this node with another node. If there is a source section (see * {@link #getSourceSection()}) associated with this node, it is transferred to the new node. * @@ -244,6 +271,27 @@ return replace(newNode, ""); } + private void replaceHelper(Node newNode, CharSequence reason) { + CompilerAsserts.neverPartOfCompilation(); + if (this.getParent() == null) { + throw new IllegalStateException("This node cannot be replaced, because it does not yet have a parent."); + } + if (sourceSection != null && newNode.getSourceSection() == null) { + // Pass on the source section to the new node. + newNode.assignSourceSection(sourceSection); + } + // (aw) need to set parent *before* replace, so that (unsynchronized) getRootNode() + // will always find the root node + newNode.parent = this.parent; + if (NodeUtil.replaceChild(this.parent, this, newNode)) { + this.parent.adoptHelper(newNode); + } else { + this.parent.adoptUnadoptedHelper(newNode); + } + reportReplace(this, newNode, reason); + onReplace(newNode, reason); + } + /** * Checks if this node is properly adopted by a parent and can be replaced. * @@ -435,4 +483,32 @@ sb.append("@").append(Integer.toHexString(hashCode())); return sb.toString(); } + + public final void atomic(Runnable closure) { + RootNode rootNode = getRootNode(); + if (rootNode != null) { + synchronized (rootNode) { + closure.run(); + } + } else { + closure.run(); + } + } + + public final T atomic(Callable closure) { + try { + RootNode rootNode = getRootNode(); + if (rootNode != null) { + synchronized (rootNode) { + return closure.call(); + } + } else { + return closure.call(); + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Sun Mar 30 16:08:33 2014 +0200 @@ -122,6 +122,20 @@ return unsafe.getObject(node, offset); } } + + @Override + public int hashCode() { + return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NodeField) { + NodeField other = (NodeField) obj; + return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind); + } + return false; + } } /** @@ -198,6 +212,21 @@ public long[] getChildrenOffsets() { return childrenOffsets; } + + @Override + public int hashCode() { + return Arrays.hashCode(fields) ^ Arrays.hashCode(childOffsets) ^ Arrays.hashCode(childrenOffsets) ^ ((Long) parentOffset).hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NodeClass) { + NodeClass other = (NodeClass) obj; + return Arrays.equals(fields, other.fields) && Arrays.equals(childOffsets, other.childOffsets) && Arrays.equals(childrenOffsets, other.childrenOffsets) && + parentOffset == other.parentOffset; + } + return false; + } } static class NodeIterator implements Iterator { diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java Sun Mar 30 16:08:33 2014 +0200 @@ -24,6 +24,8 @@ */ package com.oracle.truffle.api.nodes; +import com.oracle.truffle.api.*; + /** * An exception that should be thrown if the return value cannot be represented as a value of the * return type. The Truffle optimizer has special knowledge of this exception class and will never @@ -41,6 +43,7 @@ * @param result the alternative result */ public UnexpectedResultException(Object result) { + CompilerDirectives.transferToInterpreter(); this.result = result; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -62,7 +62,7 @@ */ protected void internalAppendProbe(InstrumentationProbeNode newProbeNode) { if (next == null) { - this.next = adoptChild(newProbeNode); + this.next = insert(newProbeNode); } else { next.internalAppendProbe(newProbeNode); } @@ -75,7 +75,7 @@ if (oldProbeNode.next == null) { this.next = null; } else { - this.next = adoptChild(oldProbeNode.next); + this.next = insert(oldProbeNode.next); oldProbeNode.next = null; } } else { diff -r 1617b1e25d31 -r 000c283d7b71 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 Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Sun Mar 30 16:08:33 2014 +0200 @@ -98,13 +98,17 @@ return param.getLocalName(); } - private static CodeTree createAccessChild(NodeExecutionData targetExecution) { + private static CodeTree createAccessChild(NodeExecutionData targetExecution, String thisReference) { + String reference = thisReference; + if (reference == null) { + reference = "this"; + } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); Element accessElement = targetExecution.getChild().getAccessElement(); if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { - builder.string("this.").string(targetExecution.getChild().getName()); + builder.string(reference).string(".").string(targetExecution.getChild().getName()); } else if (accessElement.getKind() == ElementKind.FIELD) { - builder.string("this.").string(accessElement.getSimpleName().toString()); + builder.string(reference).string(".").string(accessElement.getSimpleName().toString()); } else { throw new AssertionError(); } @@ -357,7 +361,7 @@ nodes.nullLiteral(); arguments.string(valueName(parameter.getPreviousParameter())); } - nodes.tree(createAccessChild(executionData)); + nodes.tree(createAccessChild(executionData, null)); arguments.string(valueName(parameter)); empty = false; } @@ -928,12 +932,6 @@ var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); clazz.add(var); - CodeExecutableElement setter = new CodeExecutableElement(modifiers(PROTECTED), context.getType(void.class), "setNext0"); - setter.getParameters().add(new CodeVariableElement(clazz.asType(), "next0")); - CodeTreeBuilder builder = setter.createBuilder(); - builder.statement("this.next0 = adoptChild(next0)"); - clazz.add(setter); - CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getPolymorphicSpecialization()); clazz.add(genericCachedExecute); @@ -948,41 +946,21 @@ } if (needsInvokeCopyConstructorMethod()) { - clazz.add(createInvokeCopyConstructor(clazz.asType(), null)); - clazz.add(createCopyPolymorphicConstructor(clazz.asType())); + clazz.add(createCopy(clazz.asType(), null)); } if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) { clazz.add(createGenericExecute(node, rootGroup)); } - clazz.add(createGetCost(node, null, NodeCost.MONOMORPHIC)); } protected boolean needsInvokeCopyConstructorMethod() { return getModel().getNode().isPolymorphic(); } - protected CodeExecutableElement createGetCost(NodeData node, SpecializationData specialization, NodeCost cost) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getNodeCost(), "getCost"); - - TypeMirror nodeInfoKind = context.getTruffleTypes().getNodeCost(); - - CodeTreeBuilder builder = method.createBuilder(); - if (node.isPolymorphic() && specialization == null) { - // assume next0 exists - builder.startIf().string("next0 != null && next0.getCost() != ").staticReference(nodeInfoKind, "UNINITIALIZED").end(); - builder.startBlock(); - builder.startReturn().staticReference(nodeInfoKind, "POLYMORPHIC").end(); - builder.end(); - } - - builder.startReturn().staticReference(nodeInfoKind, cost.name()).end(); - return method; - } - - protected CodeExecutableElement createInvokeCopyConstructor(TypeMirror baseType, SpecializationData specialization) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), baseType, "invokeCopyConstructor"); + protected CodeExecutableElement createCopy(TypeMirror baseType, SpecializationData specialization) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), baseType, "copyWithConstructor"); if (specialization == null) { method.getModifiers().add(ABSTRACT); } else { @@ -998,36 +976,6 @@ return method; } - protected CodeExecutableElement createCopyPolymorphicConstructor(TypeMirror baseType) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), baseType, "copyPolymorphic"); - CodeTreeBuilder builder = method.createBuilder(); - CodeTreeBuilder nullBuilder = builder.create(); - CodeTreeBuilder oldBuilder = builder.create(); - CodeTreeBuilder resetBuilder = builder.create(); - - for (ActualParameter param : getModel().getSignatureParameters()) { - NodeExecutionData execution = param.getSpecification().getExecution(); - - CodeTree access = createAccessChild(execution); - - String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName()); - oldBuilder.declaration(execution.getChild().getNodeData().getNodeType(), oldName, access); - nullBuilder.startStatement().tree(access).string(" = null").end(); - resetBuilder.startStatement().tree(access).string(" = ").string(oldName).end(); - } - - builder.tree(oldBuilder.getRoot()); - builder.tree(nullBuilder.getRoot()); - - builder.startStatement().type(baseType).string(" copy = "); - builder.startCall("invokeCopyConstructor").end(); - builder.end(); - - builder.tree(resetBuilder.getRoot()); - builder.startReturn().string("copy").end(); - return method; - } - private List createImplicitChildrenAccessors() { NodeData node = getModel().getNode(); // Map> expectTypes = new HashMap<>(); @@ -1210,7 +1158,6 @@ String fieldName = var.getSimpleName().toString(); CodeTree init = createStaticCast(builder, child, fieldName); - init = createAdoptChild(builder, var.asType(), init); builder.string("this.").string(fieldName).string(" = ").tree(init); builder.end(); @@ -1229,18 +1176,6 @@ return CodeTreeBuilder.singleString(fieldName); } - private CodeTree createAdoptChild(CodeTreeBuilder parent, TypeMirror type, CodeTree value) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (Utils.isAssignable(getContext(), type, getContext().getTruffleTypes().getNode())) { - builder.string("adoptChild(").tree(value).string(")"); - } else if (Utils.isAssignable(getContext(), type, getContext().getTruffleTypes().getNodeArray())) { - builder.string("adoptChildren(").tree(value).string(")"); - } else { - builder.tree(value); - } - return builder.getRoot(); - } - private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor, ExecutableElement sourceSectionConstructor) { CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); CodeTreeBuilder builder = method.createBuilder(); @@ -1261,7 +1196,7 @@ if (Utils.isAssignable(getContext(), varType, getContext().getTruffleTypes().getNodeArray())) { copyAccess += ".clone()"; } - CodeTree init = createAdoptChild(builder, varType, CodeTreeBuilder.singleString(copyAccess)); + CodeTree init = CodeTreeBuilder.singleString(copyAccess); builder.startStatement().string("this.").string(varName).string(" = ").tree(init).end(); } @@ -1293,7 +1228,7 @@ private CodeExecutableElement createGenericExecuteAndSpecialize(final NodeData node, SpecializationGroup rootGroup) { TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_SPECIALIZE_NAME); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), genericReturnType, EXECUTE_SPECIALIZE_NAME); method.addParameter(new CodeVariableElement(getContext().getType(int.class), "minimumState")); addInternalValueParameters(method, node.getGenericSpecialization(), true, false); method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason")); @@ -1354,7 +1289,7 @@ private CodeExecutableElement createGenericExecute(NodeData node, SpecializationGroup group) { TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_GENERIC_NAME); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), genericReturnType, EXECUTE_GENERIC_NAME); if (!node.needsFrame(getContext())) { method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath())); @@ -1829,11 +1764,16 @@ String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization()); CodeTreeBuilder builder = parent.create(); - builder.declaration(getElement().asType(), "currentCopy", currentNode + ".copyPolymorphic()"); + builder.declaration(getElement().asType(), "currentCopy", currentNode + ".copyWithConstructor()"); + for (ActualParameter param : getModel().getSignatureParameters()) { + NodeExecutionData execution = param.getSpecification().getExecution(); + builder.startStatement().tree(createAccessChild(execution, "currentCopy")).string(" = ").nullLiteral().end(); + } + builder.startStatement().string("currentCopy.next0 = ").startNew(uninitializedName).string("currentCopy").end().end(); + builder.declaration(polyClassName, "polymorphic", builder.create().startNew(polyClassName).string(currentNode).end()); + builder.startStatement().string("polymorphic.next0 = ").string("currentCopy").end(); builder.startStatement().startCall(currentNode, "replace").string("polymorphic").string("message").end().end(); - builder.startStatement().startCall("polymorphic", "setNext0").string("currentCopy").end().end(); - builder.startStatement().startCall("currentCopy", "setNext0").startNew(uninitializedName).string(currentNode).end().end().end(); builder.startReturn(); builder.startCall("currentCopy.next0", EXECUTE_POLYMORPHIC_NAME); @@ -2313,7 +2253,7 @@ private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, ActualParameter unexpectedParameter) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); if (targetExecution != null) { - builder.tree(createAccessChild(targetExecution)); + builder.tree(createAccessChild(targetExecution, null)); builder.string("."); } @@ -2478,7 +2418,7 @@ } CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node), baseType, false); - clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.NONE)); + clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.POLYMORPHIC)); for (ActualParameter polymorphParameter : polymorph.getSignatureParameters()) { if (!polymorphParameter.getTypeSystemType().isGeneric()) { @@ -2521,11 +2461,10 @@ } if (needsInvokeCopyConstructorMethod()) { - clazz.add(createInvokeCopyConstructor(nodeGen.asType(), specialization)); + clazz.add(createCopy(nodeGen.asType(), specialization)); } createCachedExecuteMethods(specialization); - clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.NONE)); } private ExecutableElement createUpdateType(ActualParameter parameter) { @@ -2571,7 +2510,7 @@ } else if (specialization.isUninitialized()) { cost = NodeCost.UNINITIALIZED; } else if (specialization.isPolymorphic()) { - cost = NodeCost.NONE; + cost = NodeCost.POLYMORPHIC; } else if (specialization.isSpecialized()) { cost = NodeCost.MONOMORPHIC; } else { @@ -2607,13 +2546,7 @@ getElement().add(createUpdateTypes(nodeGen.asType())); } if (needsInvokeCopyConstructorMethod()) { - clazz.add(createInvokeCopyConstructor(nodeGen.asType(), specialization)); - } - - if (specialization.isGeneric()) { - clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.MEGAMORPHIC)); - } else if (specialization.isUninitialized()) { - clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.UNINITIALIZED)); + clazz.add(createCopy(nodeGen.asType(), specialization)); } } @@ -2644,7 +2577,7 @@ if (node.isPolymorphic()) { if (specialization.isSpecialized() || specialization.isPolymorphic()) { - builder.statement("this.next0 = adoptChild(copy.next0)"); + builder.statement("this.next0 = copy.next0"); } } if (superConstructor != null) { @@ -2739,9 +2672,9 @@ builder.end(); builder.startElseBlock(); - builder.startStatement().startCall("setNext0"); + builder.startStatement().string("next0 = "); builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end(); - builder.end().end(); + builder.end(); CodeTreeBuilder specializeCall = new CodeTreeBuilder(builder); specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -52,7 +52,7 @@ super(null, frameDescriptor); /* Deep copy the body before any specialization occurs during execution. */ this.uninitializedBodyNode = NodeUtil.cloneNode(bodyNode); - this.bodyNode = adoptChild(bodyNode); + this.bodyNode = bodyNode; this.name = name; } diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -53,9 +53,9 @@ protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { this.cachedFunction = cachedFunction; - this.callCachedTargetNode = adoptChild(Truffle.getRuntime().createCallNode(cachedFunction.getCallTarget())); + this.callCachedTargetNode = Truffle.getRuntime().createCallNode(cachedFunction.getCallTarget()); this.cachedTargetStable = cachedFunction.getCallTargetStable(); - this.nextNode = adoptChild(next); + this.nextNode = next; } /** diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -48,9 +48,9 @@ @Child protected SLAbstractDispatchNode dispatchNode; private SLInvokeNode(SLExpressionNode functionNode, SLExpressionNode[] argumentNodes, SLAbstractDispatchNode dispatchNode) { - this.functionNode = adoptChild(functionNode); - this.argumentNodes = adoptChildren(argumentNodes); - this.dispatchNode = adoptChild(dispatchNode); + this.functionNode = functionNode; + this.argumentNodes = argumentNodes; + this.dispatchNode = dispatchNode; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -45,7 +45,7 @@ * It is a Truffle requirement to call adoptChildren(), which performs all the necessary * steps to add the new children to the node tree. */ - this.bodyNodes = adoptChildren(bodyNodes); + this.bodyNodes = bodyNodes; } /** diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -54,7 +54,7 @@ * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps * to add the new child to the node tree. */ - this.bodyNode = adoptChild(bodyNode); + this.bodyNode = bodyNode; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -57,9 +57,9 @@ * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps * to add the new child to the node tree. */ - this.conditionNode = adoptChild(conditionNode); - this.thenPartNode = adoptChild(thenPartNode); - this.elsePartNode = adoptChild(elsePartNode); + this.conditionNode = conditionNode; + this.thenPartNode = thenPartNode; + this.elsePartNode = elsePartNode; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -40,7 +40,7 @@ @Child private SLExpressionNode valueNode; public SLReturnNode(SLExpressionNode valueNode) { - this.valueNode = adoptChild(valueNode); + this.valueNode = valueNode; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -55,8 +55,8 @@ * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps * to add the new child to the node tree. */ - this.conditionNode = adoptChild(conditionNode); - this.bodyNode = adoptChild(bodyNode); + this.conditionNode = conditionNode; + this.bodyNode = bodyNode; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -16,7 +16,7 @@ * 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 + * 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. */ diff -r 1617b1e25d31 -r 000c283d7b71 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/demo/SLAddWithoutSpecializationNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/demo/SLAddWithoutSpecializationNode.java Wed Mar 19 11:43:57 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/demo/SLAddWithoutSpecializationNode.java Sun Mar 30 16:08:33 2014 +0200 @@ -42,8 +42,8 @@ @Child private SLExpressionNode rightNode; public SLAddWithoutSpecializationNode(SLExpressionNode leftNode, SLExpressionNode rightNode) { - this.leftNode = adoptChild(leftNode); - this.rightNode = adoptChild(rightNode); + this.leftNode = leftNode; + this.rightNode = rightNode; } @Override diff -r 1617b1e25d31 -r 000c283d7b71 graal/findbugsExcludeFilter.xml --- a/graal/findbugsExcludeFilter.xml Wed Mar 19 11:43:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r 1617b1e25d31 -r 000c283d7b71 mx/mx_graal.py --- a/mx/mx_graal.py Wed Mar 19 11:43:57 2014 +0100 +++ b/mx/mx_graal.py Sun Mar 30 16:08:33 2014 +0200 @@ -79,7 +79,8 @@ _make_eclipse_launch = False -_minVersion = mx.VersionSpec('1.7.0_04') +# @CallerSensitive introduced in 7u25 +_minVersion = mx.VersionSpec('1.7.0_25') JDK_UNIX_PERMISSIONS = 0755 @@ -583,7 +584,7 @@ if not exists(vmDir): if mx.get_os() != 'windows': chmodRecursive(jdk, JDK_UNIX_PERMISSIONS) - mx.log('Creating VM directory in JDK7: ' + vmDir) + mx.log('Creating VM directory in JDK: ' + vmDir) os.makedirs(vmDir) def filterXusage(line): @@ -647,11 +648,17 @@ env.setdefault('ALT_BOOTDIR', mx.java().jdk) # extract latest release tag for graal - tags = [x.split(' ')[0] for x in subprocess.check_output(['hg', 'tags']).split('\n') if x.startswith("graal-")] + try: + tags = [x.split(' ')[0] for x in subprocess.check_output(['hg', 'tags']).split('\n') if x.startswith("graal-")] + except: + # not a mercurial repository or hg commands are not available. + tags = None + if tags: # extract the most recent tag tag = sorted(tags, key=lambda e: [int(x) for x in e[len("graal-"):].split('.')], reverse=True)[0] env.setdefault('USER_RELEASE_SUFFIX', tag) + if not mx._opts.verbose: runCmd.append('MAKE_VERBOSE=') env['JAVA_HOME'] = jdk @@ -784,7 +791,7 @@ matches = lambda line: len([a for a in annotations if line == a or line.startswith(a + '(')]) != 0 return p.find_classes_with_matching_source_line(pkgRoot, matches, includeInnerClasses) -def _extract_VM_args(args, allowClasspath=False, useDoubleDash=False): +def _extract_VM_args(args, allowClasspath=False, useDoubleDash=False, defaultAllVMArgs=True): """ Partitions a command line into a leading sequence of HotSpot VM options and the rest. """ @@ -805,7 +812,10 @@ remainder = args[i:] return vmArgs, remainder - return args, [] + if defaultAllVMArgs: + return args, [] + else: + return [], args def _run_tests(args, harness, annotations, testfile): @@ -991,34 +1001,34 @@ with VM('graal', 'fastdebug'): t = Task('BootstrapWithSystemAssertions:fastdebug') - vm(['-esa', '-version']) + vm(['-esa', '-XX:-TieredCompilation', '-version']) tasks.append(t.stop()) with VM('graal', 'fastdebug'): - t = Task('NoTieredBootstrapWithSystemAssertions:fastdebug') - vm(['-esa', '-XX:-TieredCompilation', '-version']) + t = Task('BootstrapWithSystemAssertionsNoCoop:fastdebug') + vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version']) tasks.append(t.stop()) with VM('graal', 'product'): t = Task('BootstrapWithGCVerification:product') out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write - vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) + vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) tasks.append(t.stop()) with VM('graal', 'product'): t = Task('BootstrapWithG1GCVerification:product') out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write - vm(['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) + vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) tasks.append(t.stop()) with VM('graal', 'product'): t = Task('BootstrapWithRegisterPressure:product') - vm(['-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version']) + vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version']) tasks.append(t.stop()) with VM('graal', 'product'): t = Task('BootstrapWithImmutableCode:product') - vm(['-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version']) + vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version']) tasks.append(t.stop()) with VM('server', 'product'): # hosted mode @@ -1027,11 +1037,7 @@ tasks.append(t.stop()) for vmbuild in ['fastdebug', 'product']: - for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): - if 'eclipse' in str(test) and mx.java().version >= mx.VersionSpec('1.8'): - # DaCapo eclipse doesn't run under JDK8 - continue - + for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): t = Task(str(test) + ':' + vmbuild) if not test.test('graal'): t.abort(test.name + ' Failed') @@ -1139,6 +1145,16 @@ t.abort('Checkstyle warnings were found') tasks.append(t.stop()) + t = Task('Checkheaders') + if checkheaders([]) != 0: + t.abort('Checkheaders warnings were found') + tasks.append(t.stop()) + + t = Task('FindBugs') + if findbugs([]) != 0: + t.abort('FindBugs warnings were found') + tasks.append(t.stop()) + if exists('jacoco.exec'): os.unlink('jacoco.exec') @@ -1680,20 +1696,53 @@ nonTestProjects = [p for p in mx.projects() if not p.name.endswith('.test') and not p.name.endswith('.jtt')] outputDirs = [p.output_dir() for p in nonTestProjects] findbugsResults = join(_graal_home, 'findbugs.results') - exitcode = mx.run_java(['-jar', findbugsJar, '-textui', '-low', '-maxRank', '15', '-exclude', join(_graal_home, 'graal', 'findbugsExcludeFilter.xml'), - '-auxclasspath', mx.classpath([p.name for p in nonTestProjects]), '-output', findbugsResults, '-progress', '-exitcode'] + args + outputDirs, nonZeroIsFatal=False) + + cmd = ['-jar', findbugsJar, '-textui', '-low', '-maxRank', '15'] + if sys.stdout.isatty(): + cmd.append('-progress') + cmd = cmd + ['-auxclasspath', mx.classpath([p.name for p in nonTestProjects]), '-output', findbugsResults, '-exitcode'] + args + outputDirs + exitcode = mx.run_java(cmd, nonZeroIsFatal=False) if exitcode != 0: with open(findbugsResults) as fp: mx.log(fp.read()) os.unlink(findbugsResults) return exitcode +def checkheaders(args): + """check Java source headers against any required pattern""" + failures = {} + for p in mx.projects(): + if p.native: + continue + + csConfig = join(mx.project(p.checkstyleProj).dir, '.checkstyle_checks.xml') + dom = xml.dom.minidom.parse(csConfig) + for module in dom.getElementsByTagName('module'): + if module.getAttribute('name') == 'RegexpHeader': + for prop in module.getElementsByTagName('property'): + if prop.getAttribute('name') == 'header': + value = prop.getAttribute('value') + matcher = re.compile(value, re.MULTILINE) + for sourceDir in p.source_dirs(): + for root, _, files in os.walk(sourceDir): + for name in files: + if name.endswith('.java') and name != 'package-info.java': + f = join(root, name) + with open(f) as fp: + content = fp.read() + if not matcher.match(content): + failures[f] = csConfig + for n, v in failures.iteritems(): + mx.log('{}: header does not match RegexpHeader defined in {}'.format(n, v)) + return len(failures) + def mx_init(suite): commands = { 'build': [build, ''], 'buildvars': [buildvars, ''], 'buildvms': [buildvms, '[-options]'], 'c1visualizer' : [c1visualizer, ''], + 'checkheaders': [checkheaders, ''], 'clean': [clean, ''], 'findbugs': [findbugs, ''], 'generateZshCompletion' : [generateZshCompletion, ''], diff -r 1617b1e25d31 -r 000c283d7b71 mx/projects --- a/mx/projects Wed Mar 19 11:43:57 2014 +0100 +++ b/mx/projects Sun Mar 30 16:08:33 2014 +0200 @@ -13,6 +13,9 @@ library@CHECKSTYLE@path=lib/checkstyle-5.5-all.jar library@CHECKSTYLE@urls=jar:http://sourceforge.net/projects/checkstyle/files/checkstyle/5.5/checkstyle-5.5-bin.zip/download!/checkstyle-5.5/checkstyle-5.5-all.jar +library@FINDBUGS@path=lib/findbugs-3.0.0-dev-20131204-e3cbbd5.jar +library@FINDBUGS@urls=jar:http://sourceforge.net/projects/findbugs/files/findbugs/3.0.0/findbugs-3.0.0-dev-20131204-e3cbbd5.zip/download!/findbugs-3.0.0-dev-20131204-e3cbbd5/lib/findbugs.jar + library@DACAPO@path=lib/dacapo-9.12-bach.jar library@DACAPO@urls=http://softlayer.dl.sourceforge.net/project/dacapobench/9.12-bach/dacapo-9.12-bach.jar @@ -38,6 +41,10 @@ library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar +library@JAVA_ALLOCATION_INSTRUMENTER@path=lib/java-allocation-instrumenter.jar +library@JAVA_ALLOCATION_INSTRUMENTER@urls=http://lafo.ssw.uni-linz.ac.at/java-allocation-instrumenter/java-allocation-instrumenter-8f0db117e64e.jar +library@JAVA_ALLOCATION_INSTRUMENTER@sha1=64c0a5329fbcb8284640e58d83252e0a3b08c23e + distribution@GRAAL@path=graal.jar distribution@GRAAL@dependencies=\ com.oracle.graal.hotspot.amd64,\ @@ -47,12 +54,13 @@ com.oracle.graal.hotspot.sparc,\ com.oracle.graal.hotspot,\ com.oracle.graal.hotspot.hsail +distribution@GRAAL@excludeLibs=FINDBUGS # graal.api.runtime project@com.oracle.graal.api.runtime@subDir=graal project@com.oracle.graal.api.runtime@sourceDirs=src project@com.oracle.graal.api.runtime@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.api.runtime@javaCompliance=1.7 +project@com.oracle.graal.api.runtime@javaCompliance=1.8 project@com.oracle.graal.api.runtime@workingSets=API,Graal # graal.api.test @@ -60,14 +68,14 @@ project@com.oracle.graal.api.test@sourceDirs=src project@com.oracle.graal.api.test@dependencies=JUNIT,com.oracle.graal.api.runtime project@com.oracle.graal.api.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.api.test@javaCompliance=1.7 +project@com.oracle.graal.api.test@javaCompliance=1.8 project@com.oracle.graal.api.test@workingSets=API,Graal,Test # graal.api.meta project@com.oracle.graal.api.meta@subDir=graal project@com.oracle.graal.api.meta@sourceDirs=src project@com.oracle.graal.api.meta@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.api.meta@javaCompliance=1.7 +project@com.oracle.graal.api.meta@javaCompliance=1.8 project@com.oracle.graal.api.meta@workingSets=API,Graal # graal.api.meta.test @@ -75,7 +83,7 @@ project@com.oracle.graal.api.meta.test@sourceDirs=src project@com.oracle.graal.api.meta.test@dependencies=JUNIT,com.oracle.graal.runtime,com.oracle.graal.java project@com.oracle.graal.api.meta.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.api.meta.test@javaCompliance=1.7 +project@com.oracle.graal.api.meta.test@javaCompliance=1.8 project@com.oracle.graal.api.meta.test@workingSets=API,Graal,Test # graal.api.meta.jdk8.test @@ -91,7 +99,7 @@ project@com.oracle.graal.api.code@sourceDirs=src project@com.oracle.graal.api.code@dependencies=com.oracle.graal.api.meta project@com.oracle.graal.api.code@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.api.code@javaCompliance=1.7 +project@com.oracle.graal.api.code@javaCompliance=1.8 project@com.oracle.graal.api.code@workingSets=API,Graal # graal.api.replacements @@ -99,7 +107,7 @@ project@com.oracle.graal.api.replacements@sourceDirs=src project@com.oracle.graal.api.replacements@dependencies=com.oracle.graal.api.meta project@com.oracle.graal.api.replacements@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.api.replacements@javaCompliance=1.7 +project@com.oracle.graal.api.replacements@javaCompliance=1.8 project@com.oracle.graal.api.replacements@workingSets=API,Graal,Replacements # graal.service.processor @@ -107,7 +115,7 @@ project@com.oracle.graal.service.processor@sourceDirs=src project@com.oracle.graal.service.processor@dependencies=com.oracle.graal.api.runtime project@com.oracle.graal.service.processor@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.service.processor@javaCompliance=1.7 +project@com.oracle.graal.service.processor@javaCompliance=1.8 project@com.oracle.graal.service.processor@workingSets=Codegen,HotSpot # graal.amd64 @@ -115,7 +123,7 @@ project@com.oracle.graal.amd64@sourceDirs=src project@com.oracle.graal.amd64@dependencies=com.oracle.graal.api.code project@com.oracle.graal.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.amd64@javaCompliance=1.7 +project@com.oracle.graal.amd64@javaCompliance=1.8 project@com.oracle.graal.amd64@workingSets=Graal,AMD64 # graal.ptx @@ -123,7 +131,7 @@ project@com.oracle.graal.ptx@sourceDirs=src project@com.oracle.graal.ptx@dependencies=com.oracle.graal.api.code project@com.oracle.graal.ptx@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.ptx@javaCompliance=1.7 +project@com.oracle.graal.ptx@javaCompliance=1.8 project@com.oracle.graal.ptx@workingSets=Graal,PTX # graal.sparc @@ -131,16 +139,16 @@ project@com.oracle.graal.sparc@sourceDirs=src project@com.oracle.graal.sparc@dependencies=com.oracle.graal.api.code project@com.oracle.graal.sparc@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.sparc@javaCompliance=1.7 +project@com.oracle.graal.sparc@javaCompliance=1.8 project@com.oracle.graal.sparc@workingSets=Graal,SPARC # graal.hotspot project@com.oracle.graal.hotspot@subDir=graal project@com.oracle.graal.hotspot@sourceDirs=src -project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer +project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer,com.oracle.graal.baseline project@com.oracle.graal.hotspot@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot@annotationProcessors=com.oracle.graal.replacements.verifier,com.oracle.graal.service.processor -project@com.oracle.graal.hotspot@javaCompliance=1.7 +project@com.oracle.graal.hotspot@javaCompliance=1.8 project@com.oracle.graal.hotspot@workingSets=Graal,HotSpot # graal.hotspot.amd64 @@ -149,7 +157,7 @@ project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.compiler.amd64,com.oracle.graal.hotspot,com.oracle.graal.replacements.amd64 project@com.oracle.graal.hotspot.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.amd64@annotationProcessors=com.oracle.graal.service.processor -project@com.oracle.graal.hotspot.amd64@javaCompliance=1.7 +project@com.oracle.graal.hotspot.amd64@javaCompliance=1.8 project@com.oracle.graal.hotspot.amd64@workingSets=Graal,HotSpot,AMD64 # graal.hotspot.sparc @@ -158,25 +166,25 @@ project@com.oracle.graal.hotspot.sparc@dependencies=com.oracle.graal.compiler.sparc project@com.oracle.graal.hotspot.sparc@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.sparc@annotationProcessors=com.oracle.graal.service.processor -project@com.oracle.graal.hotspot.sparc@javaCompliance=1.7 +project@com.oracle.graal.hotspot.sparc@javaCompliance=1.8 project@com.oracle.graal.hotspot.sparc@workingSets=Graal,HotSpot,SPARC # graal.hotspot.ptx project@com.oracle.graal.hotspot.ptx@subDir=graal project@com.oracle.graal.hotspot.ptx@sourceDirs=src -project@com.oracle.graal.hotspot.ptx@dependencies=com.oracle.graal.ptx,com.oracle.graal.compiler.ptx,com.oracle.graal.hotspot +project@com.oracle.graal.hotspot.ptx@dependencies=com.oracle.graal.ptx,com.oracle.graal.compiler.ptx,com.oracle.graal.hotspot,com.oracle.graal.gpu project@com.oracle.graal.hotspot.ptx@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.ptx@annotationProcessors=com.oracle.graal.service.processor -project@com.oracle.graal.hotspot.ptx@javaCompliance=1.7 +project@com.oracle.graal.hotspot.ptx@javaCompliance=1.8 project@com.oracle.graal.hotspot.ptx@workingSets=Graal,HotSpot,PTX # graal.hotspot.hsail project@com.oracle.graal.hotspot.hsail@subDir=graal project@com.oracle.graal.hotspot.hsail@sourceDirs=src -project@com.oracle.graal.hotspot.hsail@dependencies=com.oracle.graal.replacements.hsail,com.oracle.graal.hotspot +project@com.oracle.graal.hotspot.hsail@dependencies=com.oracle.graal.replacements.hsail,com.oracle.graal.hotspot,com.oracle.graal.gpu project@com.oracle.graal.hotspot.hsail@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.hsail@annotationProcessors=com.oracle.graal.service.processor -project@com.oracle.graal.hotspot.hsail@javaCompliance=1.7 +project@com.oracle.graal.hotspot.hsail@javaCompliance=1.8 project@com.oracle.graal.hotspot.hsail@workingSets=Graal,HotSpot,PTX # graal.hotspot.server @@ -184,7 +192,7 @@ project@com.oracle.graal.hotspot.server@sourceDirs=src project@com.oracle.graal.hotspot.server@dependencies=com.oracle.graal.hotspot project@com.oracle.graal.hotspot.server@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.hotspot.server@javaCompliance=1.7 +project@com.oracle.graal.hotspot.server@javaCompliance=1.8 project@com.oracle.graal.hotspot.server@workingSets=Graal,HotSpot # graal.hotspot.test @@ -192,7 +200,7 @@ project@com.oracle.graal.hotspot.test@sourceDirs=src project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.replacements.test,com.oracle.graal.hotspot project@com.oracle.graal.hotspot.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.hotspot.test@javaCompliance=1.7 +project@com.oracle.graal.hotspot.test@javaCompliance=1.8 project@com.oracle.graal.hotspot.test@workingSets=Graal,HotSpot,Test # graal.hotspot.jdk8.test @@ -208,14 +216,14 @@ project@com.oracle.graal.hotspot.amd64.test@sourceDirs=src project@com.oracle.graal.hotspot.amd64.test@dependencies=com.oracle.graal.asm.amd64,com.oracle.graal.compiler.test project@com.oracle.graal.hotspot.amd64.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.hotspot.amd64.test@javaCompliance=1.7 +project@com.oracle.graal.hotspot.amd64.test@javaCompliance=1.8 project@com.oracle.graal.hotspot.amd64.test@workingSets=Graal,HotSpot,AMD64,Test # graal.options project@com.oracle.graal.options@subDir=graal project@com.oracle.graal.options@sourceDirs=src project@com.oracle.graal.options@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.options@javaCompliance=1.7 +project@com.oracle.graal.options@javaCompliance=1.8 project@com.oracle.graal.options@annotationProcessorForDependents=true project@com.oracle.graal.options@workingSets=Graal,Codegen @@ -224,14 +232,14 @@ project@com.oracle.graal.options.test@sourceDirs=src project@com.oracle.graal.options.test@dependencies=com.oracle.graal.options,JUNIT project@com.oracle.graal.options.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.options.test@javaCompliance=1.7 +project@com.oracle.graal.options.test@javaCompliance=1.8 project@com.oracle.graal.options.test@workingSets=Graal # graal.graph project@com.oracle.graal.graph@subDir=graal project@com.oracle.graal.graph@sourceDirs=src -project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug,com.oracle.graal.api.code -project@com.oracle.graal.graph@javaCompliance=1.7 +project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug,com.oracle.graal.api.code,FINDBUGS +project@com.oracle.graal.graph@javaCompliance=1.8 project@com.oracle.graal.graph@workingSets=Graal,Graph # graal.graph.test @@ -239,14 +247,14 @@ project@com.oracle.graal.graph.test@sourceDirs=src project@com.oracle.graal.graph.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.graph.test@dependencies=JUNIT,com.oracle.graal.graph -project@com.oracle.graal.graph.test@javaCompliance=1.7 +project@com.oracle.graal.graph.test@javaCompliance=1.8 project@com.oracle.graal.graph.test@workingSets=Graal,Graph,Test # graal.debug project@com.oracle.graal.debug@subDir=graal project@com.oracle.graal.debug@sourceDirs=src project@com.oracle.graal.debug@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.debug@javaCompliance=1.7 +project@com.oracle.graal.debug@javaCompliance=1.8 project@com.oracle.graal.debug@workingSets=Graal,Debug # graal.debug.test @@ -254,7 +262,7 @@ project@com.oracle.graal.debug.test@sourceDirs=src project@com.oracle.graal.debug.test@dependencies=JUNIT,com.oracle.graal.debug project@com.oracle.graal.debug.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.debug.test@javaCompliance=1.7 +project@com.oracle.graal.debug.test@javaCompliance=1.8 project@com.oracle.graal.debug.test@workingSets=Graal,Debug,Test # graal.lir @@ -262,7 +270,7 @@ project@com.oracle.graal.lir@sourceDirs=src project@com.oracle.graal.lir@dependencies=com.oracle.graal.asm,com.oracle.graal.nodes project@com.oracle.graal.lir@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.lir@javaCompliance=1.7 +project@com.oracle.graal.lir@javaCompliance=1.8 project@com.oracle.graal.lir@workingSets=Graal,LIR # graal.lir.amd64 @@ -270,7 +278,7 @@ project@com.oracle.graal.lir.amd64@sourceDirs=src project@com.oracle.graal.lir.amd64@dependencies=com.oracle.graal.lir,com.oracle.graal.asm.amd64 project@com.oracle.graal.lir.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.lir.amd64@javaCompliance=1.7 +project@com.oracle.graal.lir.amd64@javaCompliance=1.8 project@com.oracle.graal.lir.amd64@workingSets=Graal,LIR,AMD64 # graal.lir.ptx @@ -278,7 +286,7 @@ project@com.oracle.graal.lir.ptx@sourceDirs=src project@com.oracle.graal.lir.ptx@dependencies=com.oracle.graal.asm.ptx project@com.oracle.graal.lir.ptx@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.lir.ptx@javaCompliance=1.7 +project@com.oracle.graal.lir.ptx@javaCompliance=1.8 project@com.oracle.graal.lir.ptx@workingSets=Graal,LIR,PTX # graal.lir.sparc @@ -286,7 +294,7 @@ project@com.oracle.graal.lir.sparc@sourceDirs=src project@com.oracle.graal.lir.sparc@dependencies=com.oracle.graal.asm.sparc project@com.oracle.graal.lir.sparc@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.lir.sparc@javaCompliance=1.7 +project@com.oracle.graal.lir.sparc@javaCompliance=1.8 project@com.oracle.graal.lir.sparc@workingSets=Graal,LIR,SPARC # graal.alloc @@ -294,7 +302,7 @@ project@com.oracle.graal.alloc@sourceDirs=src project@com.oracle.graal.alloc@dependencies=com.oracle.graal.nodes project@com.oracle.graal.alloc@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.alloc@javaCompliance=1.7 +project@com.oracle.graal.alloc@javaCompliance=1.8 project@com.oracle.graal.alloc@workingSets=Graal # graal.word @@ -302,7 +310,7 @@ project@com.oracle.graal.word@sourceDirs=src project@com.oracle.graal.word@dependencies=com.oracle.graal.phases project@com.oracle.graal.word@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.word@javaCompliance=1.7 +project@com.oracle.graal.word@javaCompliance=1.8 project@com.oracle.graal.word@workingSets=API,Graal # graal.replacements @@ -310,7 +318,7 @@ project@com.oracle.graal.replacements@sourceDirs=src project@com.oracle.graal.replacements@dependencies=com.oracle.graal.compiler,com.oracle.graal.java,com.oracle.graal.word project@com.oracle.graal.replacements@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.replacements@javaCompliance=1.7 +project@com.oracle.graal.replacements@javaCompliance=1.8 project@com.oracle.graal.replacements@annotationProcessors=com.oracle.graal.replacements.verifier,com.oracle.graal.service.processor project@com.oracle.graal.replacements@workingSets=Graal,Replacements @@ -319,7 +327,7 @@ project@com.oracle.graal.replacements.amd64@sourceDirs=src project@com.oracle.graal.replacements.amd64@dependencies=com.oracle.graal.replacements project@com.oracle.graal.replacements.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.replacements.amd64@javaCompliance=1.7 +project@com.oracle.graal.replacements.amd64@javaCompliance=1.8 project@com.oracle.graal.replacements.amd64@annotationProcessors=com.oracle.graal.service.processor project@com.oracle.graal.replacements.amd64@workingSets=Graal,Replacements,AMD64 @@ -328,7 +336,7 @@ project@com.oracle.graal.replacements.hsail@sourceDirs=src project@com.oracle.graal.replacements.hsail@dependencies=com.oracle.graal.compiler.hsail project@com.oracle.graal.replacements.hsail@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.replacements.hsail@javaCompliance=1.7 +project@com.oracle.graal.replacements.hsail@javaCompliance=1.8 project@com.oracle.graal.replacements.hsail@workingSets=Graal,Replacements,HSAIL # graal.replacements.test @@ -336,7 +344,7 @@ project@com.oracle.graal.replacements.test@sourceDirs=src project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.compiler.test,com.oracle.graal.replacements project@com.oracle.graal.replacements.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.replacements.test@javaCompliance=1.7 +project@com.oracle.graal.replacements.test@javaCompliance=1.8 project@com.oracle.graal.replacements.test@workingSets=Graal,Replacements,Test # graal.replacements.verifier @@ -344,7 +352,7 @@ project@com.oracle.graal.replacements.verifier@sourceDirs=src project@com.oracle.graal.replacements.verifier@dependencies=com.oracle.graal.api.replacements,com.oracle.graal.graph project@com.oracle.graal.replacements.verifier@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.replacements.verifier@javaCompliance=1.7 +project@com.oracle.graal.replacements.verifier@javaCompliance=1.8 project@com.oracle.graal.replacements.verifier@workingSets=Graal,Replacements # graal.nodes @@ -352,7 +360,7 @@ project@com.oracle.graal.nodes@sourceDirs=src project@com.oracle.graal.nodes@dependencies=com.oracle.graal.graph,com.oracle.graal.api.replacements project@com.oracle.graal.nodes@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.nodes@javaCompliance=1.7 +project@com.oracle.graal.nodes@javaCompliance=1.8 project@com.oracle.graal.nodes@annotationProcessors=com.oracle.graal.replacements.verifier project@com.oracle.graal.nodes@workingSets=Graal,Graph @@ -361,7 +369,7 @@ project@com.oracle.graal.nodes.test@sourceDirs=src project@com.oracle.graal.nodes.test@dependencies=com.oracle.graal.compiler.test project@com.oracle.graal.nodes.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.nodes.test@javaCompliance=1.7 +project@com.oracle.graal.nodes.test@javaCompliance=1.8 project@com.oracle.graal.nodes.test@workingSets=Graal,Graph # graal.phases @@ -369,7 +377,7 @@ project@com.oracle.graal.phases@sourceDirs=src project@com.oracle.graal.phases@dependencies=com.oracle.graal.nodes,com.oracle.graal.options project@com.oracle.graal.phases@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.phases@javaCompliance=1.7 +project@com.oracle.graal.phases@javaCompliance=1.8 project@com.oracle.graal.phases@workingSets=Graal,Phases # graal.phases.common @@ -377,7 +385,7 @@ project@com.oracle.graal.phases.common@sourceDirs=src project@com.oracle.graal.phases.common@dependencies=com.oracle.graal.phases project@com.oracle.graal.phases.common@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.phases.common@javaCompliance=1.7 +project@com.oracle.graal.phases.common@javaCompliance=1.8 project@com.oracle.graal.phases.common@workingSets=Graal,Phases # graal.virtual @@ -385,7 +393,7 @@ project@com.oracle.graal.virtual@sourceDirs=src project@com.oracle.graal.virtual@dependencies=com.oracle.graal.phases.common project@com.oracle.graal.virtual@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.virtual@javaCompliance=1.7 +project@com.oracle.graal.virtual@javaCompliance=1.8 project@com.oracle.graal.virtual@workingSets=Graal,Phases # graal.loop @@ -393,7 +401,7 @@ project@com.oracle.graal.loop@sourceDirs=src project@com.oracle.graal.loop@dependencies=com.oracle.graal.phases.common project@com.oracle.graal.loop@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.loop@javaCompliance=1.7 +project@com.oracle.graal.loop@javaCompliance=1.8 project@com.oracle.graal.loop@workingSets=Graal,Phases # graal.compiler @@ -401,7 +409,7 @@ project@com.oracle.graal.compiler@sourceDirs=src project@com.oracle.graal.compiler@dependencies=com.oracle.graal.api.runtime,com.oracle.graal.virtual,com.oracle.graal.loop,com.oracle.graal.alloc,com.oracle.graal.lir project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler@javaCompliance=1.7 +project@com.oracle.graal.compiler@javaCompliance=1.8 project@com.oracle.graal.compiler@annotationProcessors=com.oracle.graal.service.processor project@com.oracle.graal.compiler@workingSets=Graal @@ -410,7 +418,7 @@ project@com.oracle.graal.compiler.amd64@sourceDirs=src project@com.oracle.graal.compiler.amd64@dependencies=com.oracle.graal.compiler,com.oracle.graal.lir.amd64 project@com.oracle.graal.compiler.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.amd64@javaCompliance=1.7 +project@com.oracle.graal.compiler.amd64@javaCompliance=1.8 project@com.oracle.graal.compiler.amd64@workingSets=Graal,AMD64 # graal.compiler.amd64.test @@ -418,7 +426,7 @@ project@com.oracle.graal.compiler.amd64.test@sourceDirs=src project@com.oracle.graal.compiler.amd64.test@dependencies=com.oracle.graal.compiler.test project@com.oracle.graal.compiler.amd64.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.amd64.test@javaCompliance=1.7 +project@com.oracle.graal.compiler.amd64.test@javaCompliance=1.8 project@com.oracle.graal.compiler.amd64.test@workingSets=Graal,AMD64,Test # graal.compiler.ptx @@ -426,7 +434,7 @@ project@com.oracle.graal.compiler.ptx@sourceDirs=src project@com.oracle.graal.compiler.ptx@dependencies=com.oracle.graal.lir.ptx,com.oracle.graal.compiler project@com.oracle.graal.compiler.ptx@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.ptx@javaCompliance=1.7 +project@com.oracle.graal.compiler.ptx@javaCompliance=1.8 project@com.oracle.graal.compiler.ptx@workingSets=Graal,PTX # graal.compiler.ptx.test @@ -434,7 +442,7 @@ project@com.oracle.graal.compiler.ptx.test@sourceDirs=src project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.hotspot.ptx,com.oracle.graal.compiler.test project@com.oracle.graal.compiler.ptx.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.7 +project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.8 project@com.oracle.graal.compiler.ptx.test@workingSets=Graal,PTX,Test # graal.compiler.sparc @@ -442,7 +450,7 @@ project@com.oracle.graal.compiler.sparc@sourceDirs=src project@com.oracle.graal.compiler.sparc@dependencies=com.oracle.graal.lir.sparc project@com.oracle.graal.compiler.sparc@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.sparc@javaCompliance=1.7 +project@com.oracle.graal.compiler.sparc@javaCompliance=1.8 project@com.oracle.graal.compiler.sparc@workingSets=Graal,SPARC # graal.compiler.sparc.test @@ -450,7 +458,7 @@ project@com.oracle.graal.compiler.sparc.test@sourceDirs=src project@com.oracle.graal.compiler.sparc.test@dependencies=com.oracle.graal.compiler.test project@com.oracle.graal.compiler.sparc.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.sparc.test@javaCompliance=1.7 +project@com.oracle.graal.compiler.sparc.test@javaCompliance=1.8 project@com.oracle.graal.compiler.sparc.test@workingSets=Graal,SPARC,Test # graal.runtime @@ -458,14 +466,14 @@ project@com.oracle.graal.runtime@sourceDirs=src project@com.oracle.graal.runtime@dependencies=com.oracle.graal.compiler project@com.oracle.graal.runtime@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.runtime@javaCompliance=1.7 +project@com.oracle.graal.runtime@javaCompliance=1.8 project@com.oracle.graal.runtime@workingSets=Graal # graal.bytecode project@com.oracle.graal.bytecode@subDir=graal project@com.oracle.graal.bytecode@sourceDirs=src project@com.oracle.graal.bytecode@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.bytecode@javaCompliance=1.7 +project@com.oracle.graal.bytecode@javaCompliance=1.8 project@com.oracle.graal.bytecode@workingSets=Graal,Java # graal.java @@ -473,15 +481,15 @@ project@com.oracle.graal.java@sourceDirs=src project@com.oracle.graal.java@dependencies=com.oracle.graal.phases,com.oracle.graal.bytecode project@com.oracle.graal.java@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.java@javaCompliance=1.7 +project@com.oracle.graal.java@javaCompliance=1.8 project@com.oracle.graal.java@workingSets=Graal,Java # graal.baseline project@com.oracle.graal.baseline@subDir=graal project@com.oracle.graal.baseline@sourceDirs=src -project@com.oracle.graal.baseline@dependencies=com.oracle.graal.java,com.oracle.graal.lir +project@com.oracle.graal.baseline@dependencies=com.oracle.graal.compiler,com.oracle.graal.java project@com.oracle.graal.baseline@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.baseline@javaCompliance=1.7 +project@com.oracle.graal.baseline@javaCompliance=1.8 project@com.oracle.graal.baseline@workingSets=Graal,Java # graal.java.decompiler @@ -489,7 +497,7 @@ project@com.oracle.graal.java.decompiler@sourceDirs=src project@com.oracle.graal.java.decompiler@dependencies=com.oracle.graal.java project@com.oracle.graal.java.decompiler@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.java.decompiler@javaCompliance=1.7 +project@com.oracle.graal.java.decompiler@javaCompliance=1.8 project@com.oracle.graal.java.decompiler@workingSets=Graal # graal.java.decompiler.test @@ -497,7 +505,7 @@ project@com.oracle.graal.java.decompiler.test@sourceDirs=src project@com.oracle.graal.java.decompiler.test@dependencies=JUNIT,com.oracle.graal.printer,com.oracle.graal.runtime project@com.oracle.graal.java.decompiler.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.java.decompiler.test@javaCompliance=1.7 +project@com.oracle.graal.java.decompiler.test@javaCompliance=1.8 project@com.oracle.graal.java.decompiler.test@workingSets=Graal,Test # graal.printer @@ -505,7 +513,7 @@ project@com.oracle.graal.printer@sourceDirs=src project@com.oracle.graal.printer@dependencies=com.oracle.graal.java.decompiler,com.oracle.graal.compiler project@com.oracle.graal.printer@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.printer@javaCompliance=1.7 +project@com.oracle.graal.printer@javaCompliance=1.8 project@com.oracle.graal.printer@workingSets=Graal,Graph # graal.test @@ -513,15 +521,15 @@ project@com.oracle.graal.test@sourceDirs=src project@com.oracle.graal.test@dependencies=JUNIT project@com.oracle.graal.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.test@javaCompliance=1.7 +project@com.oracle.graal.test@javaCompliance=1.8 project@com.oracle.graal.test@workingSets=Graal,Test # graal.compiler.test project@com.oracle.graal.compiler.test@subDir=graal project@com.oracle.graal.compiler.test@sourceDirs=src -project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.printer,com.oracle.graal.runtime,com.oracle.graal.baseline +project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.printer,com.oracle.graal.runtime,com.oracle.graal.baseline,JAVA_ALLOCATION_INSTRUMENTER project@com.oracle.graal.compiler.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.test@javaCompliance=1.7 +project@com.oracle.graal.compiler.test@javaCompliance=1.8 project@com.oracle.graal.compiler.test@workingSets=Graal,Test # graal.jtt @@ -529,7 +537,7 @@ project@com.oracle.graal.jtt@sourceDirs=src project@com.oracle.graal.jtt@dependencies=com.oracle.graal.compiler.test project@com.oracle.graal.jtt@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.jtt@javaCompliance=1.7 +project@com.oracle.graal.jtt@javaCompliance=1.8 project@com.oracle.graal.jtt@workingSets=Graal,Test # graal.asm @@ -537,7 +545,7 @@ project@com.oracle.graal.asm@sourceDirs=src project@com.oracle.graal.asm@dependencies=com.oracle.graal.api.code project@com.oracle.graal.asm@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.asm@javaCompliance=1.7 +project@com.oracle.graal.asm@javaCompliance=1.8 project@com.oracle.graal.asm@workingSets=Graal,Assembler # graal.asm.test @@ -545,7 +553,7 @@ project@com.oracle.graal.asm.test@sourceDirs=src project@com.oracle.graal.asm.test@dependencies=com.oracle.graal.test,com.oracle.graal.runtime project@com.oracle.graal.asm.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.asm.test@javaCompliance=1.7 +project@com.oracle.graal.asm.test@javaCompliance=1.8 project@com.oracle.graal.asm.test@workingSets=Graal,Assembler,Test # graal.asm.amd64 @@ -553,7 +561,7 @@ project@com.oracle.graal.asm.amd64@sourceDirs=src project@com.oracle.graal.asm.amd64@dependencies=com.oracle.graal.asm,com.oracle.graal.amd64 project@com.oracle.graal.asm.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.asm.amd64@javaCompliance=1.7 +project@com.oracle.graal.asm.amd64@javaCompliance=1.8 project@com.oracle.graal.asm.amd64@workingSets=Graal,Assembler,AMD64 # graal.asm.amd64.test @@ -561,57 +569,64 @@ project@com.oracle.graal.asm.amd64.test@sourceDirs=src project@com.oracle.graal.asm.amd64.test@dependencies=com.oracle.graal.asm.test,com.oracle.graal.asm.amd64 project@com.oracle.graal.asm.amd64.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.asm.amd64.test@javaCompliance=1.7 +project@com.oracle.graal.asm.amd64.test@javaCompliance=1.8 project@com.oracle.graal.asm.amd64.test@workingSets=Graal,Assembler,AMD64,Test +# graal.gpu +project@com.oracle.graal.gpu@subDir=graal +project@com.oracle.graal.gpu@sourceDirs=src +project@com.oracle.graal.gpu@dependencies=com.oracle.graal.nodes +project@com.oracle.graal.gpu@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.gpu@javaCompliance=1.8 + # graal.hsail project@com.oracle.graal.hsail@subDir=graal project@com.oracle.graal.hsail@sourceDirs=src project@com.oracle.graal.hsail@dependencies=com.oracle.graal.graph project@com.oracle.graal.hsail@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.hsail@javaCompliance=1.7 +project@com.oracle.graal.hsail@javaCompliance=1.8 # graal.lir.hsail project@com.oracle.graal.lir.hsail@subDir=graal project@com.oracle.graal.lir.hsail@sourceDirs=src project@com.oracle.graal.lir.hsail@dependencies=com.oracle.graal.lir,com.oracle.graal.asm.hsail project@com.oracle.graal.lir.hsail@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.lir.hsail@javaCompliance=1.7 +project@com.oracle.graal.lir.hsail@javaCompliance=1.8 # graal.compiler.hsail project@com.oracle.graal.compiler.hsail@subDir=graal project@com.oracle.graal.compiler.hsail@sourceDirs=src project@com.oracle.graal.compiler.hsail@dependencies=com.oracle.graal.compiler,com.oracle.graal.lir.hsail project@com.oracle.graal.compiler.hsail@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.hsail@javaCompliance=1.7 +project@com.oracle.graal.compiler.hsail@javaCompliance=1.8 # graal.compiler.hsail.test.infra - HSAIL compiler test infrastructure project@com.oracle.graal.compiler.hsail.test.infra@subDir=graal project@com.oracle.graal.compiler.hsail.test.infra@sourceDirs=src project@com.oracle.graal.compiler.hsail.test.infra@dependencies=com.oracle.graal.hotspot.hsail,JUNIT,OKRA_WITH_SIM project@com.oracle.graal.compiler.hsail.test.infra@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.hsail.test.infra@javaCompliance=1.7 +project@com.oracle.graal.compiler.hsail.test.infra@javaCompliance=1.8 # graal.compiler.hsail.test project@com.oracle.graal.compiler.hsail.test@subDir=graal project@com.oracle.graal.compiler.hsail.test@sourceDirs=src project@com.oracle.graal.compiler.hsail.test@dependencies=com.oracle.graal.compiler.hsail.test.infra,com.oracle.graal.compiler.test project@com.oracle.graal.compiler.hsail.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.compiler.hsail.test@javaCompliance=1.7 +project@com.oracle.graal.compiler.hsail.test@javaCompliance=1.8 # graal.asm.hsail project@com.oracle.graal.asm.hsail@subDir=graal project@com.oracle.graal.asm.hsail@sourceDirs=src project@com.oracle.graal.asm.hsail@dependencies=com.oracle.graal.hsail,OKRA,com.oracle.graal.asm project@com.oracle.graal.asm.hsail@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.asm.hsail@javaCompliance=1.7 +project@com.oracle.graal.asm.hsail@javaCompliance=1.8 # graal.asm.ptx project@com.oracle.graal.asm.ptx@subDir=graal project@com.oracle.graal.asm.ptx@sourceDirs=src project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.lir project@com.oracle.graal.asm.ptx@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.asm.ptx@javaCompliance=1.7 +project@com.oracle.graal.asm.ptx@javaCompliance=1.8 project@com.oracle.graal.asm.ptx@workingSets=Graal,Assembler,PTX # graal.asm.sparc @@ -619,7 +634,7 @@ project@com.oracle.graal.asm.sparc@sourceDirs=src project@com.oracle.graal.asm.sparc@dependencies=com.oracle.graal.hotspot,com.oracle.graal.sparc project@com.oracle.graal.asm.sparc@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.asm.sparc@javaCompliance=1.7 +project@com.oracle.graal.asm.sparc@javaCompliance=1.8 project@com.oracle.graal.asm.sparc@workingSets=Graal,Assembler,SPARC # truffle.api @@ -684,7 +699,7 @@ project@com.oracle.graal.truffle@sourceDirs=src project@com.oracle.graal.truffle@dependencies=com.oracle.truffle.api,com.oracle.graal.replacements,com.oracle.graal.runtime,com.oracle.graal.printer project@com.oracle.graal.truffle@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.truffle@javaCompliance=1.7 +project@com.oracle.graal.truffle@javaCompliance=1.8 project@com.oracle.graal.truffle@workingSets=Graal,Truffle # graal.truffle.test @@ -692,7 +707,7 @@ project@com.oracle.graal.truffle.test@sourceDirs=src project@com.oracle.graal.truffle.test@dependencies=com.oracle.graal.truffle,com.oracle.graal.compiler.test project@com.oracle.graal.truffle.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.truffle.test@javaCompliance=1.7 +project@com.oracle.graal.truffle.test@javaCompliance=1.8 project@com.oracle.graal.truffle.test@workingSets=Graal,Truffle,Test # graal.truffle.hotspot @@ -700,7 +715,7 @@ project@com.oracle.graal.truffle.hotspot@sourceDirs=src project@com.oracle.graal.truffle.hotspot@dependencies=com.oracle.graal.truffle,com.oracle.graal.hotspot project@com.oracle.graal.truffle.hotspot@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.truffle.hotspot@javaCompliance=1.7 +project@com.oracle.graal.truffle.hotspot@javaCompliance=1.8 project@com.oracle.graal.truffle.hotspot@annotationProcessors=com.oracle.graal.service.processor project@com.oracle.graal.truffle.hotspot@workingSets=Graal,Truffle @@ -709,6 +724,6 @@ project@com.oracle.graal.truffle.hotspot.amd64@sourceDirs=src project@com.oracle.graal.truffle.hotspot.amd64@dependencies=com.oracle.graal.truffle.hotspot,com.oracle.graal.hotspot.amd64 project@com.oracle.graal.truffle.hotspot.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.truffle.hotspot.amd64@javaCompliance=1.7 +project@com.oracle.graal.truffle.hotspot.amd64@javaCompliance=1.8 project@com.oracle.graal.truffle.hotspot.amd64@annotationProcessors=com.oracle.graal.service.processor project@com.oracle.graal.truffle.hotspot.amd64@workingSets=Graal,Truffle diff -r 1617b1e25d31 -r 000c283d7b71 mx/sanitycheck.py --- a/mx/sanitycheck.py Wed Mar 19 11:43:57 2014 +0100 +++ b/mx/sanitycheck.py Sun Mar 30 16:08:33 2014 +0200 @@ -32,7 +32,7 @@ dacapoSanityWarmup = { 'avrora': [0, 0, 3, 6, 13], 'batik': [0, 0, 5, 5, 20], - 'eclipse': [2, 4, 5, 10, 16], + 'eclipse': [0, 0, 0, 0, 0], 'fop': [4, 8, 10, 20, 30], 'h2': [0, 0, 5, 5, 8], 'jython': [0, 0, 5, 10, 13], @@ -42,17 +42,15 @@ 'sunflow': [0, 2, 5, 10, 15], 'tomcat': [0, 0, 5, 10, 15], 'tradebeans': [0, 0, 5, 10, 13], - 'tradesoap': [2, 4, 5, 10, 15], + 'tradesoap': [0, 0, 5, 10, 15], 'xalan': [0, 0, 5, 10, 18], } dacapoScalaSanityWarmup = { -# (tw) actors sometimes fails verification; hardly reproducible - 'actors': [0, 0, 0, 0, 0], -# (lstadler) apparat was disabled due to a deadlock which I think is the benchmarks fault. - 'apparat': [0, 0, 0, 0, 0], + 'actors': [0, 0, 2, 5, 5], + 'apparat': [0, 0, 2, 5, 5], 'factorie': [0, 0, 2, 5, 5], - 'kiama': [0, 0, 3, 13, 15], + 'kiama': [0, 4, 3, 13, 15], 'scalac': [0, 0, 5, 15, 20], 'scaladoc': [0, 0, 5, 15, 15], 'scalap': [0, 0, 5, 15, 20], @@ -67,7 +65,8 @@ dacapoGateBuildLevels = { 'avrora': ['product', 'fastdebug', 'debug'], 'batik': ['product', 'fastdebug', 'debug'], - 'eclipse': ['product'], + # (lewurm): does not work with JDK8 + 'eclipse': [], 'fop': ['fastdebug', 'debug'], 'h2': ['product', 'fastdebug', 'debug'], 'jython': ['product', 'fastdebug', 'debug'], @@ -77,7 +76,8 @@ 'sunflow': ['fastdebug', 'debug'], 'tomcat': ['product', 'fastdebug', 'debug'], 'tradebeans': ['product', 'fastdebug', 'debug'], - # tradesoap is too unreliable for the gate, often crashing with "java.net.BindException: Address already in use" + # tradesoap is too unreliable for the gate, often crashing with concurrency problems: + # http://sourceforge.net/p/dacapobench/bugs/99/ 'tradesoap': [], 'xalan': ['product', 'fastdebug', 'debug'], } @@ -86,7 +86,7 @@ 'actors': ['product', 'fastdebug', 'debug'], 'apparat': ['product', 'fastdebug', 'debug'], 'factorie': ['product', 'fastdebug', 'debug'], - 'kiama': ['product', 'fastdebug', 'debug'], + 'kiama': ['fastdebug', 'debug'], 'scalac': ['product', 'fastdebug', 'debug'], 'scaladoc': ['product', 'fastdebug', 'debug'], 'scalap': ['product', 'fastdebug', 'debug'], diff -r 1617b1e25d31 -r 000c283d7b71 mxtool/mx.py --- a/mxtool/mx.py Wed Mar 19 11:43:57 2014 +0100 +++ b/mxtool/mx.py Sun Mar 30 16:08:33 2014 +0200 @@ -40,6 +40,7 @@ import xml.parsers.expat import shutil, re, xml.dom.minidom import pipes +import difflib from collections import Callable from threading import Thread from argparse import ArgumentParser, REMAINDER @@ -53,14 +54,14 @@ _primary_suite_path = None _primary_suite = None _opts = None -_java = None +_java_homes = None _warn = False """ A distribution is a jar or zip file containing the output from one or more Java projects. """ class Distribution: - def __init__(self, suite, name, path, deps): + def __init__(self, suite, name, path, deps, excludedLibs): self.suite = suite self.name = name self.path = path.replace('/', os.sep) @@ -68,6 +69,14 @@ self.path = join(suite.dir, self.path) self.deps = deps self.update_listeners = set() + self.excludedLibs = excludedLibs + + def sorted_deps(self, includeLibs=False): + try: + excl = [library(d) for d in self.excludedLibs] + except SystemExit as e: + abort('invalid excluded library for {} distribution: {}'.format(self.name, e)) + return [d for d in sorted_deps(self.deps, includeLibs=includeLibs) if d not in excl] def __str__(self): return self.name @@ -116,6 +125,13 @@ self.workingSets = workingSets self.dir = d + # Verify that a JDK exists for this project if its compliance level is + # less than the compliance level of the default JDK + jdk = java(self.javaCompliance) + if jdk is None and self.javaCompliance < java().javaCompliance: + abort('Cannot find ' + str(self.javaCompliance) + ' JDK required by ' + name + '. ' + + 'Specify it with --extra-java-homes option or EXTRA_JAVA_HOMES environment variable.') + # Create directories for projects that don't yet exist if not exists(d): os.mkdir(d) @@ -606,7 +622,8 @@ for name, attrs in distsMap.iteritems(): path = attrs.pop('path') deps = pop_list(attrs, 'dependencies') - d = Distribution(self, name, path, deps) + exclLibs = pop_list(attrs, 'excludeLibs') + d = Distribution(self, name, path, deps, exclLibs) d.__dict__.update(attrs) self.dists.append(d) @@ -900,6 +917,8 @@ """ l = _libs.get(name) if l is None and fatalIfMissing: + if _projects.get(name): + abort(name + ' is a project, not a library') abort('library named ' + name + ' not found') return l @@ -1035,7 +1054,8 @@ self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@', default=[]) self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@', default=[]) self.add_argument('--user-home', help='users home directory', metavar='', default=os.path.expanduser('~')) - self.add_argument('--java-home', help='bootstrap JDK installation directory (must be JDK 6 or later)', metavar='') + self.add_argument('--java-home', help='primary JDK directory (must be JDK 7 or later)', metavar='') + self.add_argument('--extra-java-homes', help='secondary JDK directories separated by "' + os.pathsep + '"', metavar='') self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='', default=[]) self.add_argument('--kill-with-sigquit', action='store_true', dest='killwithsigquit', help='send sigquit first before killing child processes') if get_os() != 'windows': @@ -1060,6 +1080,8 @@ if opts.java_home is None: opts.java_home = os.environ.get('JAVA_HOME') + if opts.extra_java_homes is None: + opts.extra_java_homes = os.environ.get('EXTRA_JAVA_HOMES') if opts.java_home is None or opts.java_home == '': opts.java_home = _handle_missing_java_home() @@ -1088,12 +1110,21 @@ msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0]) return msg + '\n' -def java(): +def java(requiredCompliance=None): """ Get a JavaConfig object containing Java commands launch details. + If requiredCompliance is None, the compliance level specified by --java-home/JAVA_HOME + is returned. Otherwise, the JavaConfig exactly matching requiredCompliance is returned + or None if there is no exact match. """ - assert _java is not None - return _java + assert _java_homes + if not requiredCompliance: + return _java_homes[0] + for java in _java_homes: + if java.javaCompliance == requiredCompliance: + return java + return None + def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, addDefaultArgs=True): return run(java().format_cmd(args, addDefaultArgs), nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd) @@ -1349,9 +1380,9 @@ A JavaConfig object encapsulates info on how Java commands are run. """ class JavaConfig: - def __init__(self, opts): - self.jdk = opts.java_home - self.debug_port = opts.java_dbg_port + def __init__(self, java_home, java_dbg_port): + self.jdk = java_home + self.debug_port = java_dbg_port self.jar = exe_suffix(join(self.jdk, 'bin', 'jar')) self.java = exe_suffix(join(self.jdk, 'bin', 'java')) self.javac = exe_suffix(join(self.jdk, 'bin', 'javac')) @@ -1360,7 +1391,7 @@ self._bootclasspath = None if not exists(self.java): - abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java) + abort('Java launcher does not exist: ' + self.java) def delAtAndSplit(s): return shlex.split(s.lstrip('@')) @@ -1388,6 +1419,14 @@ if self.debug_port is not None: self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)] + def __hash__(self): + return hash(self.jdk) + + def __cmp__(self, other): + if isinstance(other, JavaConfig): + return cmp(self.javaCompliance, other.javaCompliance) + raise TypeError() + def format_cmd(self, args, addDefaultArgs): if addDefaultArgs: return [self.java] + self.processArgs(args) @@ -1498,6 +1537,7 @@ _kill_process_group(p.pid, sig=signal.SIGQUIT) time.sleep(0.1) + def abort(codeOrMessage): """ Aborts the program with a SystemExit exception. @@ -1623,14 +1663,12 @@ if not suppliedParser: parser = ArgumentParser(prog='mx build') - javaCompliance = java().javaCompliance - 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('--source', dest='compliance', help='Java compliance level for projects without an explicit one', default=str(javaCompliance)) + 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)') parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)') @@ -1709,9 +1747,12 @@ continue # skip building this Java project if its Java compliance level is "higher" than the configured JDK - if javaCompliance < p.javaCompliance: - log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, p.javaCompliance)) + requiredCompliance = p.javaCompliance if p.javaCompliance else JavaCompliance(args.compliance) if args.compliance else None + jdk = java(requiredCompliance) + 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) @@ -1816,14 +1857,11 @@ toBeDeleted = [argfileName] try: - compliance = str(p.javaCompliance) if p.javaCompliance is not None else args.compliance if jdtJar is None: log('Compiling Java sources for {0} with javac...'.format(p.name)) - - - javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir] - if java().debug_port is not None: - javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] + javacCmd = [jdk.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir] + 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] @@ -1833,9 +1871,9 @@ else: log('Compiling Java sources for {0} with JDT...'.format(p.name)) - jdtArgs = [java().java, '-Xmx1g'] - if java().debug_port is not None: - jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] + jdtArgs = [jdk.java, '-Xmx1g'] + if jdk.debug_port is not None: + jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)] jdtArgs += ['-jar', jdtJar, '-' + compliance, @@ -1911,13 +1949,19 @@ projects = [project(name) for name in args.projects.split(',')] class Batch: - def __init__(self, settingsFile): - self.path = settingsFile + def __init__(self, settingsDir, javaCompliance): + self.path = join(settingsDir, 'org.eclipse.jdt.core.prefs') + self.javaCompliance = javaCompliance self.javafiles = list() + with open(join(settingsDir, 'org.eclipse.jdt.ui.prefs')) as fp: + jdtUiPrefs = fp.read() + self.removeTrailingWhitespace = 'sp_cleanup.remove_trailing_whitespaces_all=true' in jdtUiPrefs + if self.removeTrailingWhitespace: + assert 'sp_cleanup.remove_trailing_whitespaces=true' in jdtUiPrefs and 'sp_cleanup.remove_trailing_whitespaces_ignore_empty=false' in jdtUiPrefs def settings(self): with open(self.path) as fp: - return fp.read() + return fp.read() + java(self.javaCompliance).java + str(self.removeTrailingWhitespace) class FileInfo: def __init__(self, path): @@ -1926,12 +1970,25 @@ self.content = fp.read() self.times = (os.path.getatime(path), os.path.getmtime(path)) - def update(self): + def update(self, removeTrailingWhitespace): with open(self.path) as fp: content = fp.read() + + if self.content != content: + # Only apply *after* formatting to match the order in which the IDE does it + if removeTrailingWhitespace: + content, n = re.subn(r'[ \t]+$', '', content, flags=re.MULTILINE) + if n != 0 and self.content == content: + # undo on-disk changes made by the Eclipse formatter + with open(self.path, 'w') as fp: + fp.write(content) + if self.content != content: + self.diff = difflib.unified_diff(self.content.splitlines(1), content.splitlines(1)) self.content = content return True + + # reset access and modification time of file os.utime(self.path, self.times) modified = list() @@ -1941,7 +1998,7 @@ continue sourceDirs = p.source_dirs() - batch = Batch(join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs')) + batch = Batch(join(p.dir, '.settings'), p.javaCompliance) if not exists(batch.path): if _opts.verbose: @@ -1960,13 +2017,21 @@ if res is not batch: res.javafiles = res.javafiles + batch.javafiles + print "we have: " + str(len(batches)) + " batches" for batch in batches.itervalues(): - run([args.eclipse_exe, '-nosplash', '-application', 'org.eclipse.jdt.core.JavaCodeFormatter', '-config', batch.path] + [f.path for f in batch.javafiles]) + run([args.eclipse_exe, + '-nosplash', + '-application', + 'org.eclipse.jdt.core.JavaCodeFormatter', + '-vm', java(batch.javaCompliance).java, + '-config', batch.path] + + [f.path for f in batch.javafiles]) for fi in batch.javafiles: - if fi.update(): + if fi.update(batch.removeTrailingWhitespace): modified.append(fi) log('{0} files were modified'.format(len(modified))) + if len(modified) != 0: arcbase = _primary_suite.dir if args.backup: @@ -1975,6 +2040,8 @@ for fi in modified: name = os.path.relpath(fi.path, arcbase) log(' - {0}'.format(name)) + log('Changes:') + log(''.join(fi.diff)) if args.backup: arcname = name.replace(os.sep, '/') zf.writestr(arcname, fi.content) @@ -2090,7 +2157,7 @@ try: zf = zipfile.ZipFile(tmp, 'w') - for dep in sorted_deps(d.deps, includeLibs=True): + for dep in d.sorted_deps(includeLibs=True): if dep.isLibrary(): l = dep # merge library jar into distribution jar @@ -2110,7 +2177,8 @@ else: p = dep # skip a Java project if its Java compliance level is "higher" than the configured JDK - if java().javaCompliance < p.javaCompliance: + jdk = java(p.javaCompliance) + if not jdk: log('Excluding {0} from {2} (Java compliance level {1} required)'.format(p.name, p.javaCompliance, d.path)) continue @@ -2291,7 +2359,8 @@ abort('ERROR: .checkstyle for Project {0} is missing'.format(p.name)) # skip checking this Java project if its Java compliance level is "higher" than the configured JDK - if java().javaCompliance < p.javaCompliance: + jdk = java(p.javaCompliance) + if not jdk: log('Excluding {0} from checking (Java compliance level {1} required)'.format(p.name, p.javaCompliance)) continue @@ -2707,7 +2776,7 @@ projToDist = dict() for dist in _dists.values(): - distDeps = sorted_deps(dist.deps) + distDeps = dist.sorted_deps() for p in distDeps: projToDist[p.name] = (dist, [dep.name for dep in distDeps]) @@ -2715,6 +2784,10 @@ if p.native: continue + if not java(p.javaCompliance): + log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance)) + continue + if not exists(p.dir): os.makedirs(p.dir) @@ -2862,20 +2935,41 @@ if not exists(settingsDir): os.mkdir(settingsDir) + # collect the defaults from mxtool + defaultEclipseSettingsDir = join(dirname(__file__), 'eclipse-settings') + esdict = {} + if exists(defaultEclipseSettingsDir): + for name in os.listdir(defaultEclipseSettingsDir): + if isfile(join(defaultEclipseSettingsDir, name)): + esdict[name] = os.path.abspath(join(defaultEclipseSettingsDir, name)) + + # check for suite overrides eclipseSettingsDir = join(p.suite.mxDir, 'eclipse-settings') if exists(eclipseSettingsDir): for name in os.listdir(eclipseSettingsDir): - if name == "org.eclipse.jdt.apt.core.prefs" and not len(p.annotation_processors()) > 0: - continue - path = join(eclipseSettingsDir, name) - if isfile(path): - with open(join(eclipseSettingsDir, name)) as f: - content = f.read() - content = content.replace('${javaCompliance}', str(p.javaCompliance)) - if len(p.annotation_processors()) > 0: - content = content.replace('org.eclipse.jdt.core.compiler.processAnnotations=disabled', 'org.eclipse.jdt.core.compiler.processAnnotations=enabled') - update_file(join(settingsDir, name), content) - files.append(join(settingsDir, name)) + if isfile(join(eclipseSettingsDir, name)): + esdict[name] = os.path.abspath(join(eclipseSettingsDir, name)) + + # check for project overrides + projectSettingsDir = join(p.dir, 'eclipse-settings') + if exists(projectSettingsDir): + for name in os.listdir(projectSettingsDir): + if isfile(join(projectSettingsDir, name)): + esdict[name] = os.path.abspath(join(projectSettingsDir, name)) + + # copy a possibly modified file to the project's .settings directory + for name, path in esdict.iteritems(): + # ignore this file altogether if this project has no annotation processors + if name == "org.eclipse.jdt.apt.core.prefs" and not len(p.annotation_processors()) > 0: + continue + + with open(path) as f: + content = f.read() + content = content.replace('${javaCompliance}', str(p.javaCompliance)) + if len(p.annotation_processors()) > 0: + content = content.replace('org.eclipse.jdt.core.compiler.processAnnotations=disabled', 'org.eclipse.jdt.core.compiler.processAnnotations=enabled') + update_file(join(settingsDir, name), content) + files.append(join(settingsDir, name)) if len(p.annotation_processors()) > 0: out = XMLDoc() @@ -2938,7 +3032,8 @@ launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'}) launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn}) launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'}) - launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java().jdk}) + launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java(p.javaCompliance).jdk}) + launchOut.element('mapEntry', {'key' : 'EXTRA_JAVA_HOMES', 'value' : _opts.extra_java_homes}) launchOut.close('mapAttribute') if refresh: @@ -3185,6 +3280,7 @@ updated = False files = [] libFiles = [] + jdks = set() for p in suite.projects: if p.native: continue @@ -3195,13 +3291,21 @@ if not exists(join(p.dir, 'nbproject')): os.makedirs(join(p.dir, 'nbproject')) + jdk = java(p.javaCompliance) + + if not jdk: + log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance)) + continue + + jdks.add(jdk) + out = XMLDoc() out.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'}) out.element('description', data='Builds, tests, and runs the project ' + p.name + '.') out.element('import', {'file' : 'nbproject/build-impl.xml'}) out.open('target', {'name' : '-post-compile'}) out.open('exec', {'executable' : sys.executable}) - out.element('env', {'key' : 'JAVA_HOME', 'value' : java().jdk}) + out.element('env', {'key' : 'JAVA_HOME', 'value' : jdk.jdk}) out.element('arg', {'value' : os.path.abspath(__file__)}) out.element('arg', {'value' : 'archive'}) out.element('arg', {'value' : '@GRAAL'}) @@ -3256,7 +3360,7 @@ files.append(join(p.dir, 'nbproject', 'project.xml')) out = StringIO.StringIO() - jdkPlatform = 'JDK_' + str(java().version) + jdkPlatform = 'JDK_' + str(jdk.version) annotationProcessorEnabled = "false" annotationProcessorReferences = "" @@ -3319,7 +3423,7 @@ manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF mkdist.disabled=false -platforms.""" + jdkPlatform + """.home=""" + java().jdk + """ +platforms.""" + jdkPlatform + """.home=""" + jdk.jdk + """ platform.active=""" + jdkPlatform + """ run.classpath=\\ ${javac.classpath}:\\ @@ -3399,7 +3503,9 @@ if updated: log('If using NetBeans:') - log(' 1. Ensure that a platform named "JDK_' + str(java().version) + '" is defined (Tools -> Java Platforms)') + log(' 1. Ensure that the following platform(s) are defined (Tools -> Java Platforms):') + for jdk in jdks: + log(' JDK_' + str(jdk.version)) log(' 2. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)') _zip_files(files, suite.dir, configZip.path) @@ -3570,7 +3676,7 @@ windowTitle = ['-windowtitle', p.name + ' javadoc'] try: log('Generating {2} for {0} in {1}'.format(p.name, out, docDir)) - run([java().javadoc, memory, + run([java(p.javaCompliance).javadoc, memory, '-XDignore.symbol.file', '-classpath', cp, '-quiet', @@ -3599,7 +3705,7 @@ sp += p.source_dirs() names.append(p.name) - links = ['-link', 'http://docs.oracle.com/javase/' + str(_java.javaCompliance.value) + '/docs/api/'] + links = ['-link', 'http://docs.oracle.com/javase/' + str(java().javaCompliance.value) + '/docs/api/'] out = join(_primary_suite.dir, docDir) if args.base is not None: out = join(args.base, docDir) @@ -4079,9 +4185,16 @@ opts, commandAndArgs = _argParser._parse_cmd_line() - global _opts, _java + global _opts, _java_homes _opts = opts - _java = JavaConfig(opts) + defaultJdk = JavaConfig(opts.java_home, opts.java_dbg_port) + _java_homes = [defaultJdk] + if opts.extra_java_homes: + for java_home in opts.extra_java_homes.split(os.pathsep): + extraJdk = JavaConfig(java_home, opts.java_dbg_port) + if extraJdk > defaultJdk: + abort('Secondary JDK ' + extraJdk.jdk + ' has higher compliance level than default JDK ' + defaultJdk.jdk) + _java_homes.append(extraJdk) for s in suites(): s._post_init(opts) diff -r 1617b1e25d31 -r 000c283d7b71 src/cpu/sparc/vm/graalGlobals_sparc.hpp --- a/src/cpu/sparc/vm/graalGlobals_sparc.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/cpu/sparc/vm/graalGlobals_sparc.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -45,7 +45,7 @@ define_pd_global(intx, NewSizeThreadIncrease, 4*K ); define_pd_global(uintx,MetaspaceSize, 12*M ); define_pd_global(bool, NeverActAsServerClassMachine, false); -define_pd_global(uint64_t,MaxRAM, 1ULL*G); +define_pd_global(uint64_t,MaxRAM, 128ULL*G); define_pd_global(bool, CICompileOSR, true ); define_pd_global(bool, ProfileTraps, true ); define_pd_global(bool, UseOnStackReplacement, true ); @@ -57,7 +57,7 @@ define_pd_global(uintx,CodeCacheMinBlockLength, 4); define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); define_pd_global(intx, TypeProfileWidth, 8); -define_pd_global(intx, MethodProfileWidth, 4); +define_pd_global(intx, MethodProfileWidth, 0); #endif // COMPILERGRAAL #endif // CPU_SPARC_VM_GRAALGLOBALS_SPARC_HPP diff -r 1617b1e25d31 -r 000c283d7b71 src/cpu/x86/vm/graalGlobals_x86.hpp --- a/src/cpu/x86/vm/graalGlobals_x86.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/cpu/x86/vm/graalGlobals_x86.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -45,7 +45,7 @@ define_pd_global(intx, NewSizeThreadIncrease, 4*K ); define_pd_global(uintx,MetaspaceSize, 12*M ); define_pd_global(bool, NeverActAsServerClassMachine, false); -define_pd_global(uint64_t,MaxRAM, 1ULL*G); +define_pd_global(uint64_t,MaxRAM, 128ULL*G); define_pd_global(bool, CICompileOSR, true ); define_pd_global(bool, ProfileTraps, true ); define_pd_global(bool, UseOnStackReplacement, true ); @@ -57,7 +57,7 @@ define_pd_global(uintx,CodeCacheMinBlockLength, 4); define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); define_pd_global(intx, TypeProfileWidth, 8); -define_pd_global(intx, MethodProfileWidth, 4); +define_pd_global(intx, MethodProfileWidth, 0); #endif // COMPILERGRAAL #endif // CPU_X86_VM_GRAALGLOBALS_X86_HPP diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/gpu_hsail.cpp --- a/src/gpu/hsail/vm/gpu_hsail.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/gpu/hsail/vm/gpu_hsail.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -25,15 +25,22 @@ #include "precompiled.hpp" #include "runtime/javaCalls.hpp" #include "runtime/gpu.hpp" +#include "runtime/deoptimization.hpp" +#include "gpu_hsail.hpp" +#include "utilities/debug.hpp" +#include "utilities/exceptions.hpp" #include "hsail/vm/gpu_hsail.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" #include "graal/graalEnv.hpp" #include "graal/graalCompiler.hpp" #include "graal/graalJavaAccess.hpp" #include "hsailKernelArguments.hpp" +#include "hsailJavaCallArguments.hpp" +#include "code/pcDesc.hpp" +#include "code/scopeDesc.hpp" +#include "graal/graalVMToCompiler.hpp" +#include "gpu_hsail_Frame.hpp" // Entry to GPU native method implementation that transitions current thread to '_thread_in_vm'. #define GPU_VMENTRY(result_type, name, signature) \ @@ -53,13 +60,15 @@ #define OBJECT "Ljava/lang/Object;" #define STRING "Ljava/lang/String;" #define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" +#define HS_COMPILED_NMETHOD "Lcom/oracle/graal/hotspot/HotSpotCompiledNmethod;" +#define HS_NMETHOD "Lcom/oracle/graal/hotspot/meta/HotSpotNmethod;" // public native void executeKernel(HotSpotNmethod kernel, int jobSize, int i, int j, Object[] args) throws InvalidInstalledCodeException; JNINativeMethod Hsail::HSAIL_methods[] = { {CC"initialize", CC"()Z", FN_PTR(Hsail::initialize)}, {CC"generateKernel", CC"([B" STRING ")J", FN_PTR(Hsail::generate_kernel)}, - {CC"executeKernel0", CC"("HS_INSTALLED_CODE"I["OBJECT")Z", FN_PTR(Hsail::execute_kernel_void_1d)}, + {CC"executeKernel0", CC"("HS_INSTALLED_CODE"I["OBJECT"["OBJECT")Z", FN_PTR(Hsail::execute_kernel_void_1d)}, }; void * Hsail::_device_context = NULL; @@ -88,7 +97,7 @@ _okra_register_heap(Universe::heap()->base(), Universe::heap()->capacity()); } -GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args_handle)) +GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args_handle, jobject oops_save_handle)) ResourceMark rm; jlong nmethodValue = HotSpotInstalledCode::codeBlob(kernel_handle); @@ -104,17 +113,210 @@ SharedRuntime::throw_and_post_jvmti_exception(JavaThread::current(), vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL); } - objArrayOop args = (objArrayOop) JNIHandles::resolve(args_handle); + return execute_kernel_void_1d_internal((address) kernel, dimX, args_handle, mh, nm, oops_save_handle, CHECK_0); +GPU_END + +static void showRanges(jboolean *a, int len) { + // show ranges + bool lookFor = true; + for (int i = 0; i < len; i++) { + if ((lookFor == true) && (a[i] != 0)) { + tty->print("%d", i); + lookFor = false; + } else if ((lookFor == false) && (a[i] == 0)) { + tty->print_cr("-%d", i-1); + lookFor = true; + } + } + if (lookFor == false) { + tty->print_cr("-%d", len-1); + } +} + + +// for experimentation +static bool useDeoptInfo = true; + +jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args_handle, methodHandle& mh, nmethod *nm, jobject oops_save_handle, TRAPS) { + + ResourceMark rm(THREAD); + objArrayOop argsArray = (objArrayOop) JNIHandles::resolve(args_handle); // Reset the kernel arguments _okra_clearargs(kernel); + + HSAILDeoptimizationInfo* e; + if (useDeoptInfo) { + e = new (ResourceObj::C_HEAP, mtInternal) HSAILDeoptimizationInfo(); + e->set_never_ran_array(NEW_C_HEAP_ARRAY(jboolean, dimX, mtInternal)); + memset(e->never_ran_array(), 0, dimX * sizeof(jboolean)); + } + // This object sets up the kernel arguments - HSAILKernelArguments hka((address) kernel, mh->signature(), args, mh->is_static()); + HSAILKernelArguments hka((address) kernel, mh->signature(), argsArray, mh->is_static(), e); + + // if any object passed was null, throw an exception here + // doing this means the kernel code can avoid null checks on the object parameters. + if (hka.getFirstNullParameterIndex() >= 0) { + char buf[64]; + sprintf(buf, "Null Kernel Parameter seen, Parameter Index: %d", hka.getFirstNullParameterIndex()); + JavaThread* thread = (JavaThread*)THREAD; + thread->set_gpu_exception_bci(0); + thread->set_gpu_exception_method(mh()); + THROW_MSG_0(vmSymbols::java_lang_NullPointerException(), buf); + } // Run the kernel - return _okra_execute_with_range(kernel, dimX); -GPU_END + bool success = _okra_execute_with_range(kernel, dimX); + // check if any workitem requested a deopt + // currently we only support at most one such workitem + + + int deoptcode = e->deopt_occurred(); + if (useDeoptInfo && deoptcode != 0) { + if (deoptcode != 1) { + // error condition detected in deopt code + char msg[200]; + sprintf(msg, "deopt error detected, slot for workitem %d was not empty", -1*(deoptcode + 1)); + guarantee(deoptcode == 1, msg); + } + if (TraceGPUInteraction) { + tty->print_cr("deopt happened."); + HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[0]; + tty->print_cr("first deopter was workitem %d", pdeopt->workitem()); + } + + // Before handling any deopting workitems, save the pointers from + // the hsail frames in oops_save so they get adjusted by any + // GC. Need to do this before leaving thread_in_vm mode. + // resolve handle only needed once here (not exiting vm mode) + objArrayOop oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save_handle); + + // since slots are allocated from the beginning, we know how far to look + assert(e->num_deopts() < MAX_DEOPT_SAVE_STATES_SIZE, "deopt save state overflow"); + for (int k = 0; k < e->num_deopts(); k++) { + HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[k]; + jint workitem = pdeopt->workitem(); + if (workitem != -1) { + // this is a workitem that deopted + HSAILFrame *hsailFrame = pdeopt->first_frame(); + int dregOopMap = hsailFrame->dreg_oops_map(); + for (int bit = 0; bit < 16; bit++) { + if ((dregOopMap & (1 << bit)) != 0) { + // the dregister at this bit is an oop, save it in the array + int index = k * 16 + bit; + void* saved_oop = (void*) hsailFrame->get_d_reg(bit); + oopsSaveArray->obj_at_put(index, (oop) saved_oop); + } + } + } + } + + // Handle any deopting workitems. + int count_deoptimized = 0; + for (int k = 0; k < e->num_deopts(); k++) { + HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[k]; + + jint workitem = pdeopt->workitem(); + if (workitem != -1) { + int deoptId = pdeopt->pc_offset(); + HSAILFrame *hsailFrame = pdeopt->first_frame(); + + // update the hsailFrame from the oopsSaveArray + // re-resolve the handle + oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save_handle); + + int dregOopMap = hsailFrame->dreg_oops_map(); + for (int bit = 0; bit < 16; bit++) { + if ((dregOopMap & (1 << bit)) != 0) { + // the dregister at this bit is an oop, retrieve it from array and put back in frame + int index = k * 16 + bit; + void * dregValue = (void *) oopsSaveArray->obj_at(index); + void * oldDregValue = (void *) hsailFrame->get_d_reg(bit); + assert((oldDregValue != 0 ? dregValue != 0 : dregValue == 0) , "bad dregValue retrieved"); + if (TraceGPUInteraction) { + if (dregValue != oldDregValue) { + tty->print_cr("oop moved for $d%d, workitem %d, slot %d, old=%p, new=%p", bit, workitem, k, oldDregValue, dregValue); + } + } + hsailFrame->put_d_reg(bit, (jlong) dregValue); + } + } + + JavaValue result(T_VOID); + JavaCallArguments javaArgs; + javaArgs.set_alternative_target(nm); + javaArgs.push_int(deoptId); + javaArgs.push_long((jlong) hsailFrame); + + // override the deoptimization action with Action_none until we decide + // how to handle the other actions. + int myActionReason = Deoptimization::make_trap_request(Deoptimization::trap_request_reason(pdeopt->reason()), Deoptimization::Action_none); + javaArgs.push_int(myActionReason); + javaArgs.push_oop((oop)NULL); + if (TraceGPUInteraction) { + int dregOopMap = hsailFrame->dreg_oops_map(); + tty->print_cr("[HSAIL] Deoptimizing to host for workitem=%d (slot=%d) with deoptId=%d, frame=" INTPTR_FORMAT ", actionAndReason=%d, dregOopMap=%04x", workitem, k, deoptId, hsailFrame, myActionReason, dregOopMap); + // show the registers containing references + for (int bit = 0; bit < 16; bit++) { + if ((dregOopMap & (1 << bit)) != 0) { + tty->print_cr(" oop $d%d = %p", bit, hsailFrame->get_d_reg(bit)); + } + } + } + JavaCalls::call(&result, mh, &javaArgs, THREAD); + count_deoptimized++; + } + } + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] Deoptimizing to host completed for %d workitems", count_deoptimized); + } + + // Handle any never_ran workitems if there were any + int count_never_ran = 0; + bool handleNeverRansHere = true; + // turn off verbose trace stuff for javacall arg setup + bool savedTraceGPUInteraction = TraceGPUInteraction; + TraceGPUInteraction = false; + jboolean *never_ran_array = e->never_ran_array(); + if (handleNeverRansHere) { + for (int k = 0; k < dimX; k++) { + if (never_ran_array[k]) { + // run it as a javaCall + KlassHandle methKlass = mh->method_holder(); + Thread* THREAD = Thread::current(); + JavaValue result(T_VOID); + JavaCallArguments javaArgs; + // re-resolve the args_handle here + objArrayOop resolvedArgsArray = (objArrayOop) JNIHandles::resolve(args_handle); + // This object sets up the javaCall arguments + // the way argsArray is set up, this should work for instance methods as well + // (the receiver will be the first oop pushed) + HSAILJavaCallArguments hjca(&javaArgs, k, mh->signature(), resolvedArgsArray, mh->is_static()); + if (mh->is_static()) { + JavaCalls::call_static(&result, methKlass, mh->name(), mh->signature(), &javaArgs, THREAD); + } else { + JavaCalls::call_virtual(&result, methKlass, mh->name(), mh->signature(), &javaArgs, THREAD); + } + count_never_ran++; + } + } + TraceGPUInteraction = savedTraceGPUInteraction; + if (TraceGPUInteraction) { + tty->print_cr("%d workitems never ran, have been run via JavaCall", count_never_ran); + showRanges(never_ran_array, dimX); + } + } // end of never-ran handling + + } + + if (useDeoptInfo) { + FREE_C_HEAP_ARRAY(jboolean, e->never_ran_array(), mtInternal); + delete e; + } + return success; +} GPU_ENTRY(jlong, Hsail::generate_kernel, (JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle)) guarantee(_okra_create_kernel != NULL, "[HSAIL] Okra not linked"); @@ -172,6 +374,7 @@ if (TraceGPUInteraction) { tty->print_cr("[HSAIL] library is %s", okra_library_name); } + void *handle = os::dll_load(okra_library_name, ebuf, O_BUFLEN); // try alternate location if env variable set char *okra_lib_name_from_env_var = getenv("_OKRA_SIM_LIB_PATH_"); @@ -212,6 +415,7 @@ return true; GPU_END + bool Hsail::register_natives(JNIEnv* env) { jclass klass = env->FindClass("com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend"); if (klass == NULL) { diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/gpu_hsail.hpp --- a/src/gpu/hsail/vm/gpu_hsail.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/gpu/hsail/vm/gpu_hsail.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -25,7 +25,60 @@ #ifndef GPU_HSAIL_HPP #define GPU_HSAIL_HPP +#include "utilities/exceptions.hpp" +#include "graal/graalEnv.hpp" +// #include "graal/graalCodeInstaller.hpp" +#include "gpu_hsail_Frame.hpp" + class Hsail { + friend class gpu; + + public: + class HSAILKernelDeoptimization { + friend class VMStructs; + private: + // TODO: separate workitemid and actionAndReason out + // since they are there only once even if there are multiple frames + // for now, though we only ever have one hsail fram + jint _workitemid; + jint _actionAndReason; + // the first (innermost) "hsail frame" starts here + HSAILFrame _first_frame; + + public: + inline jint workitem() { return _workitemid; } + inline jint reason() { return _actionAndReason; } + inline jint pc_offset() { return _first_frame.pc_offset(); } + inline HSAILFrame *first_frame() { return &_first_frame; } + }; + +// 8 compute units * 40 waves per cu * wavesize 64 +#define MAX_DEOPT_SAVE_STATES_SIZE (8 * 40 * 64) + + class HSAILDeoptimizationInfo : public ResourceObj { + friend class VMStructs; + private: + jint _deopt_occurred; + jint _deopt_next_index; + jboolean * _never_ran_array; + + public: + HSAILKernelDeoptimization _deopt_save_states[MAX_DEOPT_SAVE_STATES_SIZE]; + + inline HSAILDeoptimizationInfo() { + _deopt_occurred = 0; + _deopt_next_index = 0; + } + + inline jint deopt_occurred() { + // Check that hsail did not write in the wrong place + return _deopt_occurred; + } + inline jint num_deopts() { return _deopt_next_index; } + inline jboolean *never_ran_array() { return _never_ran_array; } + inline void set_never_ran_array(jboolean *p) { _never_ran_array = p; } + }; + private: @@ -38,10 +91,18 @@ JNIEXPORT static jlong generate_kernel(JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle); // static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args); - JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv *env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args); + JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv *env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args, jobject oopsSave); + + // static native void setSimulatorSingleThreaded0(); + JNIEXPORT static void setSimulatorSingleThreaded0(JNIEnv *env, jclass); + + + static jboolean execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oopsSave, TRAPS); static void register_heap(); + static GraalEnv::CodeInstallResult install_code(Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations); + public: // Registers the implementations for the native methods in HSAILHotSpotBackend diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/gpu_hsail_Frame.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gpu/hsail/vm/gpu_hsail_Frame.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,44 @@ +#ifndef GPU_HSAIL_FRAME_HPP +#define GPU_HSAIL_FRAME_HPP + +#include "graal/graalEnv.hpp" +#include "code/debugInfo.hpp" +#include "code/location.hpp" + +// maximum registers that could be saved for now +#define MAX_SREGS 32 +#define MAX_DREGS 16 + +class HSAILFrame { + friend class VMStructs; +private: + jint _pc_offset; // The HSAIL "pc_offset" where the exception happens + jbyte _num_s_regs; + jbyte _num_d_regs; + jshort _dreg_oops_map; // bits = 1 if that dreg is an oop + jlong _save_area[MAX_SREGS/2 + MAX_DREGS]; + +public: + // Accessors + jint pc_offset() { return _pc_offset; } + jint num_s_regs() {return _num_s_regs; } + jint num_d_regs() {return _num_d_regs; } + jint dreg_oops_map() {return _dreg_oops_map; } + jlong get_d_reg(int idx) { + char *p = (char *) _save_area; + int ofst = num_s_regs() * 4 + idx * 8; + return(*(jlong *) (p + ofst)); + } + jint get_s_reg(int idx) { + char *p = (char *) _save_area; + int ofst = idx * 4; + return(*(jint *) (p + ofst)); + } + void put_d_reg(int idx, jlong val) { + char *p = (char *) _save_area; + int ofst = num_s_regs() * 4 + idx * 8; + (*(jlong *) (p + ofst)) = val; + } +}; + +#endif // GPU_HSAIL_FRAME_HPP diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/hsailArgumentsBase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gpu/hsail/vm/hsailArgumentsBase.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +#include "precompiled.hpp" +#include "hsailArgumentsBase.hpp" +#include "runtime/javaCalls.hpp" + + +// Get next java argument +oop HSAILArgumentsBase::next_arg(BasicType expectedType) { + assert(_index < _args->length(), "out of bounds"); + + oop arg = ((objArrayOop) (_args))->obj_at(_index++); + assert(expectedType == T_OBJECT || + java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); + + return arg; +} + +void HSAILArgumentsBase::do_bool() { + // Get the boxed value + oop arg = _args->obj_at(_index++); + assert(java_lang_boxing_object::is_instance(arg, T_BOOLEAN), "arg type mismatch"); + + jvalue jValue; + java_lang_boxing_object::get_value(arg, &jValue); + + pushBool(jValue.z); +} + +void HSAILArgumentsBase::do_byte() { + // Get the boxed value + oop arg = _args->obj_at(_index++); + assert(java_lang_boxing_object::is_instance(arg, T_BYTE), "arg type mismatch"); + + jvalue jValue; + java_lang_boxing_object::get_value(arg, &jValue); + + pushByte(jValue.b); +} + +void HSAILArgumentsBase::do_double() { + // Get the boxed value + oop arg = _args->obj_at(_index++); + assert(java_lang_boxing_object::is_instance(arg, T_DOUBLE), "arg type mismatch"); + + jvalue jValue; + java_lang_boxing_object::get_value(arg, &jValue); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s::do_double, _index=%d, value = %e", argsBuilderName(), _index - 1, jValue.d); + } + pushDouble(jValue.d); +} + +void HSAILArgumentsBase::do_float() { + // Get the boxed value + oop arg = _args->obj_at(_index++); + assert(java_lang_boxing_object::is_instance(arg, T_FLOAT), "arg type mismatch"); + + jvalue jValue; + java_lang_boxing_object::get_value(arg, &jValue); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s::do_float, _index=%d, value = %f", argsBuilderName(), _index - 1, jValue.f); + } + pushFloat(jValue.f); +} + +void HSAILArgumentsBase::do_int() { + // If the last parameter is an int, it is handled in a special way + // For kernel arguments we don't pass it since we use the HSAIL workitemid in place of that int value + // For javaCall arguments we pass the actual workitemid + if (isLastParameter()) { + handleFinalIntParameter(); + return; + } + + // not the final int parameter, Get the boxed int + oop arg = _args->obj_at(_index++); + assert(java_lang_boxing_object::is_instance(arg, T_INT), "arg type mismatch"); + + jvalue jValue; + java_lang_boxing_object::get_value(arg, &jValue); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s::do_int, _index=%d, value = %d", argsBuilderName(), _index - 1, jValue.i); + } + + pushInt(jValue.i); +} + +void HSAILArgumentsBase::do_long() { + // Get the boxed value + oop arg = _args->obj_at(_index++); + assert(java_lang_boxing_object::is_instance(arg, T_LONG), "arg type mismatch"); + + jvalue jValue; + java_lang_boxing_object::get_value(arg, &jValue); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s::do_long, _index=%d, value = %d", argsBuilderName(), _index - 1, jValue.j); + } + + pushLong(jValue.j); +} + +void HSAILArgumentsBase::do_array(int begin, int end) { + oop arg = _args->obj_at(_index++); + if (arg == NULL) { + recordNullObjectParameter(); + } else { + assert(arg->is_array(), "arg type mismatch"); + } + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s::do_array, _index=%d, 0x%08x, is a %s", argsBuilderName(), _index - 1, (address) arg, + arg == NULL ? "null" : arg->klass()->external_name()); + } + + pushObject(arg); +} + +void HSAILArgumentsBase::do_object() { + bool isLastParam = isLastParameter(); // determine this before incrementing _index + + oop arg = _args->obj_at(_index++); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s::do_object, _index=%d, 0x%08x is a %s", argsBuilderName(), _index - 1, (address) arg, + arg == NULL ? "null" : arg->klass()->external_name()); + } + if (arg == NULL) { + recordNullObjectParameter(); + } + + // check if this is last arg in signature + // an object as last parameter requires special handling + if (isLastParam) { + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s, trailing object ref should be object source array ref", argsBuilderName()); + } + assert(arg->is_objArray(), "arg type mismatch"); + handleFinalObjParameter(arg); + } else { + // not the final parameter, just push + pushObject(arg); + } +} + +void HSAILArgumentsBase::do_object(int begin, int end) { + do_object(); +} + +void HSAILArgumentsBase::do_void() { + return; +} + +// TODO implement other do_* + diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/hsailArgumentsBase.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gpu/hsail/vm/hsailArgumentsBase.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +#ifndef BASE_ARGUMENTS_HSAIL_HPP +#define BASE_ARGUMENTS_HSAIL_HPP + +#include "runtime/signature.hpp" + + +/*** + * Base class which iterates thru a signature and pulls from a + * objArrayOop of boxed values. Used as base for HSAILKernelArguments + * and HSAILJavaCallArguments The derived classes specify how to push + * args onto their data structure + ***/ + +class HSAILArgumentsBase : public SignatureIterator { + +public: + +private: + // Array of java argument oops + objArrayOop _args; + // Length of args array + int _length; + // Current index into _args + int _index; + // number of parameters in the signature + int _parameter_count; + + Symbol * _signature; + bool _is_static; + + // records first null parameter seen + int _first_null_parameter_index; + + // Get next java argument + oop next_arg(BasicType expectedType); + + virtual char *argsBuilderName() = 0; + virtual void pushObject(void * obj) = 0; + virtual void pushBool(jboolean z) = 0; + virtual void pushByte(jbyte b) = 0; + virtual void pushDouble(jdouble d) = 0; + virtual void pushFloat(jfloat f) = 0; + virtual void pushInt(jint i) = 0; + virtual void pushLong(jlong j) = 0; + virtual void handleFinalIntParameter() = 0; + virtual void handleFinalObjParameter(void *obj) = 0; + virtual void pushTrailingArgs() = 0; + + void recordNullObjectParameter() { + if (_first_null_parameter_index == -1) _first_null_parameter_index = _parameter_index; + } + + public: + HSAILArgumentsBase(Symbol* signature, objArrayOop args, bool is_static) : SignatureIterator(signature) { + this->_return_type = T_ILLEGAL; + _index = 0; + _args = args; + _is_static = is_static; + _signature = signature; + + _length = args->length(); + _parameter_count = ArgumentCount(signature).size(); + + _first_null_parameter_index = -1; + + } + + int getFirstNullParameterIndex() { + return _first_null_parameter_index; + } + + void collectArgs() { + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s::collectArgs, sig:%s args length=%d", argsBuilderName(), _signature->as_C_string(), _length); + } + if (!_is_static) { + // First object in args should be 'this' + oop arg = _args->obj_at(_index++); + assert(arg->is_instance() && (! arg->is_array()), "First arg should be 'this'"); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s, instance method, this " PTR_FORMAT ", is a %s", argsBuilderName(), (address) arg, arg->klass()->external_name()); + } + pushObject(arg); + } else { + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] %s, static method", argsBuilderName()); + } + } + // Iterate over the entire signature + iterate(); + + pushTrailingArgs(); + } + + void do_bool(); + void do_byte(); + void do_double(); + void do_float(); + void do_int(); + void do_long(); + void do_array(int begin, int end); + void do_object(); + void do_object(int begin, int end); + + void do_void(); + + inline void do_char() { + /* TODO : To be implemented */ + guarantee(false, "do_char:NYI"); + } + inline void do_short() { + /* TODO : To be implemented */ + guarantee(false, "do_short:NYI"); + } + + bool isLastParameter() { + return (_index == (_is_static ? _parameter_count - 1 : _parameter_count)); + } + +}; + +#endif // BASE_ARGUMENTS_HSAIL_HPP diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/hsailJavaCallArguments.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gpu/hsail/vm/hsailJavaCallArguments.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +#ifndef JAVACALL_ARGUMENTS_HSAIL_HPP +#define JAVACALL_ARGUMENTS_HSAIL_HPP + +#include "hsailArgumentsBase.hpp" +#include "runtime/javaCalls.hpp" + +class HSAILJavaCallArguments : public HSAILArgumentsBase { + +public: + +private: + // JavaCall Args to push into + JavaCallArguments *_javaArgs; + int _workitemid; + public: + HSAILJavaCallArguments(JavaCallArguments *javaArgs, int workitemid, Symbol* signature, objArrayOop args, bool is_static) : HSAILArgumentsBase(signature, args, is_static) { + _javaArgs = javaArgs; + _workitemid = workitemid; + collectArgs(); + } + virtual char *argsBuilderName() {return (char *)"HSAILJavaCallArguments";} + virtual void pushObject(void *obj) { _javaArgs->push_oop((oop) obj); } + virtual void pushBool(jboolean z) { pushInt(z); } + virtual void pushByte(jbyte b) { pushInt(b); } + virtual void pushDouble(jdouble d) { _javaArgs->push_double(d); } + virtual void pushFloat(jfloat f) { _javaArgs->push_float(f); } + virtual void pushInt(jint i) { _javaArgs->push_int(i); } + virtual void pushLong(jlong j) { _javaArgs->push_long(j); } + virtual void pushTrailingArgs() { } + + // For javaCall the final int parameter gets replaced with the workitemid + // which was passed back in the deopt info + virtual void handleFinalIntParameter() { + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] HSAILJavaCallArguments, passing workitemid %d as trailing int parameter", _workitemid); + } + pushInt(_workitemid); + } + // for kernel arguments, final obj parameter should be an object + // stream source array (already checked in the base class) so for + // a javacall we need to extract the correct obj from it based on + // the workitemid + virtual void handleFinalObjParameter(void *arg) { + objArrayOop objArrayArg = (objArrayOop) arg; + oop extractedObj = objArrayArg->obj_at(_workitemid); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] HSAILJavaCallArguments, extracted obj #%d from array, 0x%08x is a %s", + _workitemid, (address) extractedObj, + (extractedObj == NULL ? "null" : extractedObj->klass()->external_name())); + } + pushObject(extractedObj); + } + +}; + +#endif // JAVACALL_ARGUMENTS_HSAIL_HPP + diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/hsailKernelArguments.cpp --- a/src/gpu/hsail/vm/hsailKernelArguments.cpp Wed Mar 19 11:43:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2013, 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. - * - */ - -#include "precompiled.hpp" -#include "hsailKernelArguments.hpp" -#include "runtime/javaCalls.hpp" - - -// Get next java argument -oop HSAILKernelArguments::next_arg(BasicType expectedType) { - assert(_index < _args->length(), "out of bounds"); - - oop arg = ((objArrayOop) (_args))->obj_at(_index++); - assert(expectedType == T_OBJECT || - java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); - - return arg; -} - -void HSAILKernelArguments::do_bool() { - // Get the boxed value - oop arg = _args->obj_at(_index++); - assert(java_lang_boxing_object::is_instance(arg, T_BOOLEAN), "arg type mismatch"); - - jvalue jValue; - java_lang_boxing_object::get_value(arg, &jValue); - - bool pushed = Hsail::_okra_push_boolean(_kernel, jValue.z); - assert(pushed == true, "arg push failed"); -} - -void HSAILKernelArguments::do_byte() { - // Get the boxed value - oop arg = _args->obj_at(_index++); - assert(java_lang_boxing_object::is_instance(arg, T_BYTE), "arg type mismatch"); - - jvalue jValue; - java_lang_boxing_object::get_value(arg, &jValue); - - bool pushed = Hsail::_okra_push_byte(_kernel, jValue.b); - assert(pushed == true, "arg push failed"); -} - -void HSAILKernelArguments::do_double() { - // Get the boxed value - oop arg = _args->obj_at(_index++); - assert(java_lang_boxing_object::is_instance(arg, T_DOUBLE), "arg type mismatch"); - - jvalue jValue; - java_lang_boxing_object::get_value(arg, &jValue); - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_double, _index=%d, value = %e", _index - 1, jValue.d); - } - bool pushed = Hsail::_okra_push_double(_kernel, jValue.d); - assert(pushed == true, "arg push failed"); -} - -void HSAILKernelArguments::do_float() { - // Get the boxed value - oop arg = _args->obj_at(_index++); - assert(java_lang_boxing_object::is_instance(arg, T_FLOAT), "arg type mismatch"); - - jvalue jValue; - java_lang_boxing_object::get_value(arg, &jValue); - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_float, _index=%d, value = %f", _index - 1, jValue.f); - } - bool pushed = Hsail::_okra_push_float(_kernel, jValue.f); - assert(pushed == true, "float push failed"); -} - -void HSAILKernelArguments::do_int() { - // The last int is the iteration variable in an IntStream, but we don't pass it - // since we use the HSAIL workitemid in place of that int value - if (isLastParameter()) { - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::not pushing trailing int"); - } - return; - } - - // Get the boxed int - oop arg = _args->obj_at(_index++); - assert(java_lang_boxing_object::is_instance(arg, T_INT), "arg type mismatch"); - - jvalue jValue; - java_lang_boxing_object::get_value(arg, &jValue); - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_int, _index=%d, value = %d", _index - 1, jValue.i); - } - - bool pushed = Hsail::_okra_push_int(_kernel, jValue.i); - assert(pushed == true, "arg push failed"); -} - -void HSAILKernelArguments::do_long() { - // Get the boxed value - oop arg = _args->obj_at(_index++); - assert(java_lang_boxing_object::is_instance(arg, T_LONG), "arg type mismatch"); - - jvalue jValue; - java_lang_boxing_object::get_value(arg, &jValue); - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_long, _index=%d, value = %d", _index - 1, jValue.j); - } - - bool pushed = Hsail::_okra_push_long(_kernel, jValue.j); - assert(pushed == true, "arg push failed"); -} - -void HSAILKernelArguments::do_array(int begin, int end) { - oop arg = _args->obj_at(_index++); - assert(arg->is_array(), "arg type mismatch"); - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_array, _index=%d, 0x%08x, is a %s", _index - 1, (address) arg, arg->klass()->external_name()); - } - - bool pushed = Hsail::_okra_push_object(_kernel, arg); - assert(pushed == true, "arg push failed"); -} - -void HSAILKernelArguments::do_object() { - - bool isLastParam = isLastParameter(); // determine this before incrementing _index - - oop arg = _args->obj_at(_index++); - - // check if this is last arg in signature - // an object as last parameter requires an object stream source array to be passed - if (isLastParam) { - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::trailing object ref should be object source array ref"); - } - assert(arg->is_objArray(), "arg type mismatch"); - } - - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, _index=%d, 0x%08x is a %s", _index - 1, (address) arg, arg->klass()->external_name()); - } - - bool pushed = Hsail::_okra_push_object(_kernel, arg); - assert(pushed == true, "arg push failed"); -} - -void HSAILKernelArguments::do_object(int begin, int end) { - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_object(int begin, int end), begin=%d, end=%d.", begin, end); - } - do_object(); -} - -void HSAILKernelArguments::do_void() { - return; -} - -// TODO implement other do_* diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/hsailKernelArguments.hpp --- a/src/gpu/hsail/vm/hsailKernelArguments.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -25,90 +25,80 @@ #ifndef KERNEL_ARGUMENTS_HSAIL_HPP #define KERNEL_ARGUMENTS_HSAIL_HPP -#include "runtime/gpu.hpp" -#include "hsail/vm/gpu_hsail.hpp" +#include "gpu_hsail.hpp" #include "runtime/signature.hpp" +#include "hsailArgumentsBase.hpp" -class HSAILKernelArguments : public SignatureIterator { +class HSAILKernelArguments : public HSAILArgumentsBase { friend class Hsail; public: private: - // Array of java argument oops - objArrayOop _args; - // Length of args array - int _length; - // Current index into _args - int _index; // Kernel to push into address _kernel; - // number of parameters in the signature - int _parameter_count; - - bool _is_static; - - // Get next java argument - oop next_arg(BasicType expectedType); + void * _exceptionHolder; public: - HSAILKernelArguments(address kernel, Symbol* signature, objArrayOop args, bool is_static) : SignatureIterator(signature) { - this->_return_type = T_ILLEGAL; - _index = 0; - _args = args; - _kernel = kernel; - _is_static = is_static; + HSAILKernelArguments(address kernel, Symbol* signature, objArrayOop args, bool is_static, void* exceptionHolder) : HSAILArgumentsBase(signature, args, is_static) { + _kernel = kernel; + _exceptionHolder = exceptionHolder; + collectArgs(); + } + virtual char *argsBuilderName() {return (char *)"HSAILKernelArguments";} + virtual void pushObject(void *obj) { + bool pushed = Hsail::_okra_push_object(_kernel, obj); + assert(pushed == true, "arg push failed"); + } + virtual void pushBool(jboolean z) { + bool pushed = Hsail::_okra_push_boolean(_kernel, z); + assert(pushed == true, "arg push failed"); + } + virtual void pushByte(jbyte b) { + bool pushed = Hsail::_okra_push_byte(_kernel, b); + assert(pushed == true, "arg push failed"); + } - _length = args->length(); - _parameter_count = ArgumentCount(signature).size(); + virtual void pushDouble(jdouble d) { + bool pushed = Hsail::_okra_push_double(_kernel, d); + assert(pushed == true, "arg push failed"); + } - if (TraceGPUInteraction) { - char buf[O_BUFLEN]; - tty->print_cr("[HSAIL] sig:%s args length=%d, _parameter_count=%d", signature->as_C_string(buf, O_BUFLEN), _length, _parameter_count); - } - if (!_is_static) { - // First object in args should be 'this' - oop arg = args->obj_at(_index++); - assert(arg->is_instance() && (! arg->is_array()), "First arg should be 'this'"); + virtual void pushFloat(jfloat f) { + bool pushed = Hsail::_okra_push_float(_kernel, f); + assert(pushed == true, "arg push failed"); + } + + virtual void pushInt(jint i) { + bool pushed = Hsail::_okra_push_int(_kernel, i); + assert(pushed == true, "arg push failed"); + } + + virtual void pushLong(jlong j) { + bool pushed = Hsail::_okra_push_long(_kernel, j); + assert(pushed == true, "arg push failed"); + } + virtual void pushTrailingArgs() { + // Last argument is the exception info block + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] exception block=" PTR_FORMAT, _exceptionHolder); + } + pushObject(_exceptionHolder); + } + + // For kernel arguments we don't pass the final int parameter + // since we use the HSAIL workitemid instruction in place of that int value + virtual void handleFinalIntParameter() { if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] instance method, this 0x%08x, is a %s", (address) arg, arg->klass()->external_name()); - } - bool pushed = Hsail::_okra_push_object(kernel, arg); - assert(pushed == true, "'this' push failed"); - } else { - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] static method"); + tty->print_cr("[HSAIL] HSAILKernelArguments, not pushing trailing int"); } } - // Iterate over the entire signature - iterate(); - } - void do_bool(); - void do_byte(); - void do_double(); - void do_float(); - void do_int(); - void do_long(); - void do_array(int begin, int end); - void do_object(); - void do_object(int begin, int end); - - void do_void(); - - inline void do_char() { - /* TODO : To be implemented */ - guarantee(false, "do_char:NYI"); - } - inline void do_short() { - /* TODO : To be implemented */ - guarantee(false, "do_short:NYI"); - } - - bool isLastParameter() { - return (_index == (_is_static ? _parameter_count - 1 : _parameter_count)); - } - + // for kernel arguments, final obj parameter should be an object + // stream source array (already checked in the base class) so here we just pass it + virtual void handleFinalObjParameter(void *arg) { + pushObject(arg); + } }; -#endif // KERNEL_ARGUMENTS_HPP +#endif // KERNEL_ARGUMENTS_HSAIL_HPP diff -r 1617b1e25d31 -r 000c283d7b71 src/gpu/hsail/vm/vmStructs_hsail.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gpu/hsail/vm/vmStructs_hsail.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2001, 2010, 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. + * + */ + +#ifndef GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP +#define GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP + +#include "gpu_hsail.hpp" +#include "gpu_hsail_Frame.hpp" + +// These are the CPU-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_GPU_HSAIL(nonstatic_field) \ + nonstatic_field(HSAILFrame, _pc_offset, jint) \ + nonstatic_field(HSAILFrame, _num_s_regs, jbyte) \ + nonstatic_field(HSAILFrame, _save_area[0], jlong) \ + \ + nonstatic_field(Hsail::HSAILKernelDeoptimization, _workitemid, jint) \ + nonstatic_field(Hsail::HSAILKernelDeoptimization, _actionAndReason, jint) \ + nonstatic_field(Hsail::HSAILKernelDeoptimization, _first_frame, HSAILFrame) \ + \ + nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_occurred, jint) \ + nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_next_index, jint) \ + nonstatic_field(Hsail::HSAILDeoptimizationInfo, _never_ran_array, jboolean *) \ + nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_save_states[0], Hsail::HSAILKernelDeoptimization) \ + nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_save_states[1], Hsail::HSAILKernelDeoptimization) + +#define VM_TYPES_GPU_HSAIL(declare_type, declare_toplevel_type) \ + declare_toplevel_type(HSAILFrame) \ + declare_toplevel_type(HSAILFrame*) \ + declare_toplevel_type(Hsail::HSAILKernelDeoptimization) \ + declare_toplevel_type(Hsail::HSAILDeoptimizationInfo) + +#endif // GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP diff -r 1617b1e25d31 -r 000c283d7b71 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java Sun Mar 30 16:08:33 2014 +0200 @@ -29,11 +29,12 @@ import com.sun.hotspot.igv.graph.Diagram; import com.sun.hotspot.igv.graph.Figure; import com.sun.hotspot.igv.graph.InputSlot; +import com.sun.hotspot.igv.graph.OutputSlot; import java.util.HashSet; import java.util.Set; public class GraalCFGFilter extends AbstractFilter { - + @Override public String getName() { return "Graal CFG Filter"; @@ -41,16 +42,8 @@ @Override public void apply(Diagram d) { - Set
figuresToRemove = new HashSet<>(); Set connectionsToRemove = new HashSet<>(); - for (Figure f : d.getFigures()) { - final String prop = f.getProperties().get("probability"); - if (prop == null) { - figuresToRemove.add(f); - } - } - d.removeAllFigures(figuresToRemove); - + for (Figure f : d.getFigures()) { Properties p = f.getProperties(); int predCount; @@ -72,10 +65,25 @@ } } } - + for (Connection c : connectionsToRemove) { c.remove(); - System.out.println("rm " + c); } + + Set
figuresToRemove = new HashSet<>(); + next: for (Figure f : d.getFigures()) { + for (InputSlot is : f.getInputSlots()) { + if (!is.getConnections().isEmpty()) { + continue next; + } + } + for (OutputSlot os : f.getOutputSlots()) { + if (!os.getConnections().isEmpty()) { + continue next; + } + } + figuresToRemove.add(f); + } + d.removeAllFigures(figuresToRemove); } } diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/classfile/javaClasses.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -1530,6 +1530,16 @@ } return; } + + // Check for gpu exception to add as top frame + Method* gpu_method = thread->get_gpu_exception_method(); + if (gpu_method != NULL) { + jint gpu_bci = thread->get_gpu_exception_bci(); + bt.push(gpu_method, gpu_bci, CHECK); + // Clear the gpu exception state, it is not used after here + thread->set_gpu_exception_bci(0); + thread->set_gpu_exception_method(NULL); + } // Instead of using vframe directly, this version of fill_in_stack_trace // basically handles everything by hand. This significantly improved the diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/classfile/systemDictionary.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -184,6 +184,7 @@ do_klass(Long_klass, java_lang_Long, Pre ) \ \ /* Support for Graal */ \ + do_klass(CompilerThread_klass, com_oracle_graal_compiler_CompilerThread, Opt) \ do_klass(BitSet_klass, java_util_BitSet, Opt) \ /* graal.hotspot */ \ do_klass(HotSpotCompiledCode_klass, com_oracle_graal_hotspot_HotSpotCompiledCode, Opt) \ @@ -203,7 +204,6 @@ do_klass(HotSpotResolvedJavaMethod_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, Opt) \ do_klass(HotSpotResolvedObjectType_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, Opt) \ do_klass(HotSpotMonitorValue_klass, com_oracle_graal_hotspot_meta_HotSpotMonitorValue, Opt) \ - do_klass(CompilerThread_klass, com_oracle_graal_hotspot_CompilerThread, Opt) \ /* graal.api.code */ \ do_klass(Assumptions_klass, com_oracle_graal_api_code_Assumptions, Opt) \ do_klass(Assumptions_ConcreteMethod_klass, com_oracle_graal_api_code_Assumptions_ConcreteMethod, Opt) \ @@ -222,7 +222,7 @@ do_klass(CompilationResult_Mark_klass, com_oracle_graal_api_code_CompilationResult_Mark, Opt) \ do_klass(CompilationResult_Infopoint_klass, com_oracle_graal_api_code_CompilationResult_Infopoint, Opt) \ do_klass(CompilationResult_Site_klass, com_oracle_graal_api_code_CompilationResult_Site, Opt) \ - do_klass(ExternalCompilationResult_klass, com_oracle_graal_api_code_ExternalCompilationResult, Opt) \ + do_klass(ExternalCompilationResult_klass, com_oracle_graal_gpu_ExternalCompilationResult, Opt) \ do_klass(InfopointReason_klass, com_oracle_graal_api_code_InfopointReason, Opt) \ do_klass(code_Register_klass, com_oracle_graal_api_code_Register, Opt) \ do_klass(RegisterValue_klass, com_oracle_graal_api_code_RegisterValue, Opt) \ diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -288,10 +288,11 @@ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ template(selectAlternative_signature, "(ZLjava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;") \ - \ - /* Support for Graal */ \ - template(java_util_BitSet, "java/util/BitSet") \ - /* graal.hotspot */ \ + \ + /* Support for Graal */ \ + template(com_oracle_graal_compiler_CompilerThread, "com/oracle/graal/compiler/CompilerThread") \ + template(java_util_BitSet, "java/util/BitSet") \ + /* graal.hotspot */ \ template(com_oracle_graal_hotspot_HotSpotGraalRuntime, "com/oracle/graal/hotspot/HotSpotGraalRuntime") \ template(com_oracle_graal_hotspot_HotSpotKlassOop, "com/oracle/graal/hotspot/HotSpotKlassOop") \ template(com_oracle_graal_hotspot_HotSpotOptions, "com/oracle/graal/hotspot/HotSpotOptions") \ @@ -314,7 +315,6 @@ template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod") \ template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType") \ template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue, "com/oracle/graal/hotspot/meta/HotSpotMonitorValue") \ - template(com_oracle_graal_hotspot_CompilerThread, "com/oracle/graal/hotspot/CompilerThread") \ /* graal.api.meta */ \ template(com_oracle_graal_api_meta_Constant, "com/oracle/graal/api/meta/Constant") \ template(com_oracle_graal_api_meta_ConstantPool, "com/oracle/graal/api/meta/ConstantPool") \ @@ -338,7 +338,6 @@ template(com_oracle_graal_api_code_CompilationResult_Mark, "com/oracle/graal/api/code/CompilationResult$Mark") \ template(com_oracle_graal_api_code_CompilationResult_Infopoint, "com/oracle/graal/api/code/CompilationResult$Infopoint") \ template(com_oracle_graal_api_code_CompilationResult_Site, "com/oracle/graal/api/code/CompilationResult$Site") \ - template(com_oracle_graal_api_code_ExternalCompilationResult, "com/oracle/graal/api/code/ExternalCompilationResult") \ template(com_oracle_graal_api_code_InfopointReason, "com/oracle/graal/api/code/InfopointReason") \ template(com_oracle_graal_api_code_BytecodeFrame, "com/oracle/graal/api/code/BytecodeFrame") \ template(com_oracle_graal_api_code_BytecodePosition, "com/oracle/graal/api/code/BytecodePosition") \ @@ -350,6 +349,8 @@ template(com_oracle_graal_api_code_RegisterSaveLayout, "com/oracle/graal/api/code/RegisterSaveLayout") \ template(com_oracle_graal_api_code_InvalidInstalledCodeException, "com/oracle/graal/api/code/InvalidInstalledCodeException") \ template(com_oracle_graal_api_code_SpeculationLog, "com/oracle/graal/api/code/SpeculationLog") \ + /* graal.gpu */ \ + template(com_oracle_graal_gpu_ExternalCompilationResult, "com/oracle/graal/gpu/ExternalCompilationResult") \ /* graal.truffle */ \ template(com_oracle_graal_truffle_GraalTruffleRuntime, "com/oracle/graal/truffle/GraalTruffleRuntime") \ template(startCompiler_name, "startCompiler") \ diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/code/nmethod.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -105,7 +105,6 @@ // PrintC1Statistics, PrintOptoStatistics, LogVMOutput, and LogCompilation. // (In the latter two cases, they like other stats are printed to the log only.) -#ifndef PRODUCT // These variables are put into one block to reduce relocations // and make it simpler to print from the debugger. struct java_nmethod_stats_struct { @@ -233,7 +232,6 @@ unknown_java_nmethod_stats.note_nmethod(nm); } } -#endif //--------------------------------------------------------------------------------- @@ -536,7 +534,7 @@ code_buffer, frame_size, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); - NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm)); + if (nm != NULL) note_java_nmethod(nm); if (PrintAssembly && nm != NULL) { Disassembler::decode(nm); } @@ -572,7 +570,7 @@ nm = new (nmethod_size) nmethod(method(), nmethod_size, &offsets, code_buffer, frame_size); - NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm)); + if (nm != NULL) note_java_nmethod(nm); if (PrintAssembly && nm != NULL) { Disassembler::decode(nm); } @@ -652,7 +650,7 @@ // record this nmethod as dependent on this klass InstanceKlass::cast(klass)->add_dependent_nmethod(nm); } - NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm)); + if (nm != NULL) note_java_nmethod(nm); if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) { Disassembler::decode(nm); } @@ -3058,6 +3056,7 @@ void nmethod::print_nul_chk_table() { ImplicitExceptionTable(this).print(code_begin()); } +#endif // PRODUCT void nmethod::print_statistics() { ttyLocker ttyl; @@ -3078,4 +3077,3 @@ Dependencies::print_statistics(); if (xtty != NULL) xtty->tail("statistics"); } -#endif // PRODUCT diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/code/nmethod.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -694,7 +694,7 @@ // Prints a comment for one native instruction (reloc info, pc desc) void print_code_comment_on(outputStream* st, int column, address begin, address end); - static void print_statistics() PRODUCT_RETURN; + static void print_statistics(); // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/compiler/disassembler.cpp --- a/src/share/vm/compiler/disassembler.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/compiler/disassembler.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -159,397 +159,397 @@ nmethod* _nm; CodeBlob* _code; CodeStrings _strings; - outputStream* _output; - address _start, _end; - - char _option_buf[512]; - char _print_raw; - bool _print_pc; - bool _print_bytes; - address _cur_insn; - int _total_ticks; - int _bytes_per_line; // arch-specific formatting option - - static bool match(const char* event, const char* tag) { - size_t taglen = strlen(tag); - if (strncmp(event, tag, taglen) != 0) - return false; - char delim = event[taglen]; - return delim == '\0' || delim == ' ' || delim == '/' || delim == '='; - } - - void collect_options(const char* p) { - if (p == NULL || p[0] == '\0') return; - size_t opt_so_far = strlen(_option_buf); - if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return; - char* fillp = &_option_buf[opt_so_far]; - if (opt_so_far > 0) *fillp++ = ','; - strcat(fillp, p); - // replace white space by commas: - char* q = fillp; - while ((q = strpbrk(q, " \t\n")) != NULL) - *q++ = ','; - // Note that multiple PrintAssemblyOptions flags accumulate with \n, - // which we want to be changed to a comma... - } - - void print_insn_labels(); - void print_insn_bytes(address pc0, address pc); - void print_address(address value); - - public: + outputStream* _output; + address _start, _end; + + char _option_buf[512]; + char _print_raw; + bool _print_pc; + bool _print_bytes; + address _cur_insn; + int _total_ticks; + int _bytes_per_line; // arch-specific formatting option + + static bool match(const char* event, const char* tag) { + size_t taglen = strlen(tag); + if (strncmp(event, tag, taglen) != 0) + return false; + char delim = event[taglen]; + return delim == '\0' || delim == ' ' || delim == '/' || delim == '='; + } + + void collect_options(const char* p) { + if (p == NULL || p[0] == '\0') return; + size_t opt_so_far = strlen(_option_buf); + if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return; + char* fillp = &_option_buf[opt_so_far]; + if (opt_so_far > 0) *fillp++ = ','; + strcat(fillp, p); + // replace white space by commas: + char* q = fillp; + while ((q = strpbrk(q, " \t\n")) != NULL) + *q++ = ','; + // Note that multiple PrintAssemblyOptions flags accumulate with \n, + // which we want to be changed to a comma... + } + + void print_insn_labels(); + void print_insn_bytes(address pc0, address pc); + void print_address(address value); + + public: decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings()); - - address decode_instructions(address start, address end); - - void start_insn(address pc) { - _cur_insn = pc; - output()->bol(); - print_insn_labels(); - } - - void end_insn(address pc) { - address pc0 = cur_insn(); - outputStream* st = output(); - if (_print_bytes && pc > pc0) - print_insn_bytes(pc0, pc); - if (_nm != NULL) { - _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc); - // this calls reloc_string_for which calls oop::print_value_on - } - - // Output pc bucket ticks if we have any - if (total_ticks() != 0) { - address bucket_pc = FlatProfiler::bucket_start_for(pc); - if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) { - int bucket_count = FlatProfiler::bucket_count_for(pc0); - if (bucket_count != 0) { - st->bol(); - st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count); - } - } - } - // follow each complete insn by a nice newline - st->cr(); - } - - address handle_event(const char* event, address arg); - - outputStream* output() { return _output; } - address cur_insn() { return _cur_insn; } - int total_ticks() { return _total_ticks; } - void set_total_ticks(int n) { _total_ticks = n; } - const char* options() { return _option_buf; } -}; - + + address decode_instructions(address start, address end); + + void start_insn(address pc) { + _cur_insn = pc; + output()->bol(); + print_insn_labels(); + } + + void end_insn(address pc) { + address pc0 = cur_insn(); + outputStream* st = output(); + if (_print_bytes && pc > pc0) + print_insn_bytes(pc0, pc); + if (_nm != NULL) { + _nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc); + // this calls reloc_string_for which calls oop::print_value_on + } + + // Output pc bucket ticks if we have any + if (total_ticks() != 0) { + address bucket_pc = FlatProfiler::bucket_start_for(pc); + if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) { + int bucket_count = FlatProfiler::bucket_count_for(pc0); + if (bucket_count != 0) { + st->bol(); + st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count); + } + } + } + // follow each complete insn by a nice newline + st->cr(); + } + + address handle_event(const char* event, address arg); + + outputStream* output() { return _output; } + address cur_insn() { return _cur_insn; } + int total_ticks() { return _total_ticks; } + void set_total_ticks(int n) { _total_ticks = n; } + const char* options() { return _option_buf; } +}; + decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) { - memset(this, 0, sizeof(*this)); - _output = output ? output : tty; - _code = code; - if (code != NULL && code->is_nmethod()) - _nm = (nmethod*) code; + memset(this, 0, sizeof(*this)); + _output = output ? output : tty; + _code = code; + if (code != NULL && code->is_nmethod()) + _nm = (nmethod*) code; _strings.assign(c); - - // by default, output pc but not bytes: - _print_pc = true; - _print_bytes = false; - _bytes_per_line = Disassembler::pd_instruction_alignment(); - - // parse the global option string: - collect_options(Disassembler::pd_cpu_opts()); - collect_options(PrintAssemblyOptions); - - if (strstr(options(), "hsdis-")) { - if (strstr(options(), "hsdis-print-raw")) - _print_raw = (strstr(options(), "xml") ? 2 : 1); - if (strstr(options(), "hsdis-print-pc")) - _print_pc = !_print_pc; - if (strstr(options(), "hsdis-print-bytes")) - _print_bytes = !_print_bytes; - } - if (strstr(options(), "help")) { - tty->print_cr("PrintAssemblyOptions help:"); - tty->print_cr(" hsdis-print-raw test plugin by requesting raw output"); - tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml"); - tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)"); - tty->print_cr(" hsdis-print-bytes turn on instruction byte output"); - tty->print_cr("combined options: %s", options()); - } -} - -address decode_env::handle_event(const char* event, address arg) { - if (match(event, "insn")) { - start_insn(arg); - } else if (match(event, "/insn")) { - end_insn(arg); - } else if (match(event, "addr")) { - if (arg != NULL) { - print_address(arg); - return arg; - } - } else if (match(event, "mach")) { - static char buffer[32] = { 0, }; - if (strcmp(buffer, (const char*)arg) != 0 || - strlen((const char*)arg) > sizeof(buffer) - 1) { - // Only print this when the mach changes - strncpy(buffer, (const char*)arg, sizeof(buffer) - 1); - output()->print_cr("[Disassembling for mach='%s']", arg); - } - } else if (match(event, "format bytes-per-line")) { - _bytes_per_line = (int) (intptr_t) arg; - } else { - // ignore unrecognized markup - } - return NULL; -} - -// called by the disassembler to print out jump targets and data addresses -void decode_env::print_address(address adr) { - outputStream* st = _output; - - if (adr == NULL) { - st->print("NULL"); - return; - } - - int small_num = (int)(intptr_t)adr; - if ((intptr_t)adr == (intptr_t)small_num - && -1 <= small_num && small_num <= 9) { - st->print("%d", small_num); - return; - } - - if (Universe::is_fully_initialized()) { - if (StubRoutines::contains(adr)) { - StubCodeDesc* desc = StubCodeDesc::desc_for(adr); - if (desc == NULL) - desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset); - if (desc != NULL) { - st->print("Stub::%s", desc->name()); - if (desc->begin() != adr) - st->print("%+d 0x%p",adr - desc->begin(), adr); - else if (WizardMode) st->print(" " PTR_FORMAT, adr); - return; - } - st->print("Stub:: " PTR_FORMAT, adr); - return; - } - - BarrierSet* bs = Universe::heap()->barrier_set(); - if (bs->kind() == BarrierSet::CardTableModRef && - adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) { - st->print("word_map_base"); - if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr); - return; - } - - oop obj; - if (_nm != NULL - && (obj = _nm->embeddedOop_at(cur_insn())) != NULL - && (address) obj == adr - && Universe::heap()->is_in(obj) - && Universe::heap()->is_in(obj->klass())) { - julong c = st->count(); - obj->print_value_on(st); - if (st->count() == c) { - // No output. (Can happen in product builds.) - st->print("(a %s)", obj->klass()->external_name()); - } - return; - } - } - - // Fall through to a simple (hexadecimal) numeral. - st->print(PTR_FORMAT, adr); -} - -void decode_env::print_insn_labels() { - address p = cur_insn(); - outputStream* st = output(); - CodeBlob* cb = _code; - if (cb != NULL) { - cb->print_block_comment(st, p); - } + + // by default, output pc but not bytes: + _print_pc = true; + _print_bytes = false; + _bytes_per_line = Disassembler::pd_instruction_alignment(); + + // parse the global option string: + collect_options(Disassembler::pd_cpu_opts()); + collect_options(PrintAssemblyOptions); + + if (strstr(options(), "hsdis-")) { + if (strstr(options(), "hsdis-print-raw")) + _print_raw = (strstr(options(), "xml") ? 2 : 1); + if (strstr(options(), "hsdis-print-pc")) + _print_pc = !_print_pc; + if (strstr(options(), "hsdis-print-bytes")) + _print_bytes = !_print_bytes; + } + if (strstr(options(), "help")) { + tty->print_cr("PrintAssemblyOptions help:"); + tty->print_cr(" hsdis-print-raw test plugin by requesting raw output"); + tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml"); + tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)"); + tty->print_cr(" hsdis-print-bytes turn on instruction byte output"); + tty->print_cr("combined options: %s", options()); + } +} + +address decode_env::handle_event(const char* event, address arg) { + if (match(event, "insn")) { + start_insn(arg); + } else if (match(event, "/insn")) { + end_insn(arg); + } else if (match(event, "addr")) { + if (arg != NULL) { + print_address(arg); + return arg; + } + } else if (match(event, "mach")) { + static char buffer[32] = { 0, }; + if (strcmp(buffer, (const char*)arg) != 0 || + strlen((const char*)arg) > sizeof(buffer) - 1) { + // Only print this when the mach changes + strncpy(buffer, (const char*)arg, sizeof(buffer) - 1); + output()->print_cr("[Disassembling for mach='%s']", arg); + } + } else if (match(event, "format bytes-per-line")) { + _bytes_per_line = (int) (intptr_t) arg; + } else { + // ignore unrecognized markup + } + return NULL; +} + +// called by the disassembler to print out jump targets and data addresses +void decode_env::print_address(address adr) { + outputStream* st = _output; + + if (adr == NULL) { + st->print("NULL"); + return; + } + + int small_num = (int)(intptr_t)adr; + if ((intptr_t)adr == (intptr_t)small_num + && -1 <= small_num && small_num <= 9) { + st->print("%d", small_num); + return; + } + + if (Universe::is_fully_initialized()) { + if (StubRoutines::contains(adr)) { + StubCodeDesc* desc = StubCodeDesc::desc_for(adr); + if (desc == NULL) + desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset); + if (desc != NULL) { + st->print("Stub::%s", desc->name()); + if (desc->begin() != adr) + st->print("%+d 0x%p",adr - desc->begin(), adr); + else if (WizardMode) st->print(" " PTR_FORMAT, adr); + return; + } + st->print("Stub:: " PTR_FORMAT, adr); + return; + } + + BarrierSet* bs = Universe::heap()->barrier_set(); + if (bs->kind() == BarrierSet::CardTableModRef && + adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) { + st->print("word_map_base"); + if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr); + return; + } + + oop obj; + if (_nm != NULL + && (obj = _nm->embeddedOop_at(cur_insn())) != NULL + && (address) obj == adr + && Universe::heap()->is_in(obj) + && Universe::heap()->is_in(obj->klass())) { + julong c = st->count(); + obj->print_value_on(st); + if (st->count() == c) { + // No output. (Can happen in product builds.) + st->print("(a %s)", obj->klass()->external_name()); + } + return; + } + } + + // Fall through to a simple (hexadecimal) numeral. + st->print(PTR_FORMAT, adr); +} + +void decode_env::print_insn_labels() { + address p = cur_insn(); + outputStream* st = output(); + CodeBlob* cb = _code; + if (cb != NULL) { + cb->print_block_comment(st, p); + } _strings.print_block_comment(st, (intptr_t)(p - _start)); - if (_print_pc) { - st->print(" " PTR_FORMAT ": ", p); - } -} - -void decode_env::print_insn_bytes(address pc, address pc_limit) { - outputStream* st = output(); - size_t incr = 1; - size_t perline = _bytes_per_line; - if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int) - && !((uintptr_t)pc % sizeof(int)) - && !((uintptr_t)pc_limit % sizeof(int))) { - incr = sizeof(int); - if (perline % incr) perline += incr - (perline % incr); - } - while (pc < pc_limit) { - // tab to the desired column: - st->move_to(COMMENT_COLUMN); - address pc0 = pc; - address pc1 = pc + perline; - if (pc1 > pc_limit) pc1 = pc_limit; - for (; pc < pc1; pc += incr) { - if (pc == pc0) - st->print(BYTES_COMMENT); - else if ((uint)(pc - pc0) % sizeof(int) == 0) - st->print(" "); // put out a space on word boundaries - if (incr == sizeof(int)) - st->print("%08lx", *(int*)pc); - else st->print("%02x", (*pc)&0xFF); - } - st->cr(); - } -} - - -static void* event_to_env(void* env_pv, const char* event, void* arg) { - decode_env* env = (decode_env*) env_pv; - return env->handle_event(event, (address) arg); -} - -static int printf_to_env(void* env_pv, const char* format, ...) { - decode_env* env = (decode_env*) env_pv; - outputStream* st = env->output(); - size_t flen = strlen(format); - const char* raw = NULL; - if (flen == 0) return 0; - if (flen == 1 && format[0] == '\n') { st->bol(); return 1; } - if (flen < 2 || - strchr(format, '%') == NULL) { - raw = format; - } else if (format[0] == '%' && format[1] == '%' && - strchr(format+2, '%') == NULL) { - // happens a lot on machines with names like %foo - flen--; - raw = format+1; - } - if (raw != NULL) { - st->print_raw(raw, (int) flen); - return (int) flen; - } - va_list ap; - va_start(ap, format); - julong cnt0 = st->count(); - st->vprint(format, ap); - julong cnt1 = st->count(); - va_end(ap); - return (int)(cnt1 - cnt0); -} - -address decode_env::decode_instructions(address start, address end) { - _start = start; _end = end; - - assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr"); - - const int show_bytes = false; // for disassembler debugging - - //_version = Disassembler::pd_cpu_version(); - - if (!Disassembler::can_decode()) { - return NULL; - } - - // decode a series of instructions and return the end of the last instruction - - if (_print_raw) { - // Print whatever the library wants to print, w/o fancy callbacks. - // This is mainly for debugging the library itself. - FILE* out = stdout; - FILE* xmlout = (_print_raw > 1 ? out : NULL); - return use_new_version ? - (address) - (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end, - start, end - start, - NULL, (void*) xmlout, - NULL, (void*) out, - options(), 0/*nice new line*/) - : - (address) - (*Disassembler::_decode_instructions)(start, end, - NULL, (void*) xmlout, - NULL, (void*) out, - options()); - } - - return use_new_version ? - (address) - (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end, - start, end - start, - &event_to_env, (void*) this, - &printf_to_env, (void*) this, - options(), 0/*nice new line*/) - : - (address) - (*Disassembler::_decode_instructions)(start, end, - &event_to_env, (void*) this, - &printf_to_env, (void*) this, - options()); -} - - -void Disassembler::decode(CodeBlob* cb, outputStream* st) { - if (!load_library()) return; - decode_env env(cb, st); - env.output()->print_cr("----------------------------------------------------------------------"); - env.output()->print_cr("%s at [" PTR_FORMAT ", " PTR_FORMAT "] %d bytes", cb->name(), cb->code_begin(), cb->code_end(), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*)); - env.decode_instructions(cb->code_begin(), cb->code_end()); -} - -void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) { - if (!load_library()) return; - decode_env env(CodeCache::find_blob_unsafe(start), st, c); - env.decode_instructions(start, end); -} - -void Disassembler::decode(nmethod* nm, outputStream* st) { - if (!load_library()) return; - decode_env env(nm, st); - env.output()->print_cr("----------------------------------------------------------------------"); - -#ifdef SHARK - SharkEntry* entry = (SharkEntry *) nm->code_begin(); - unsigned char* p = entry->code_start(); - unsigned char* end = entry->code_limit(); -#else - unsigned char* p = nm->code_begin(); - unsigned char* end = nm->code_end(); -#endif // SHARK - - nm->method()->method_holder()->name()->print_symbol_on(env.output()); - env.output()->print("."); - nm->method()->name()->print_symbol_on(env.output()); - env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] %d bytes", p, end, ((jlong)(end - p)) * sizeof(unsigned char*)); - - // If there has been profiling, print the buckets. - if (FlatProfiler::bucket_start_for(p) != NULL) { - unsigned char* p1 = p; - int total_bucket_count = 0; - while (p1 < end) { - unsigned char* p0 = p1; - p1 += pd_instruction_alignment(); - address bucket_pc = FlatProfiler::bucket_start_for(p1); - if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1) - total_bucket_count += FlatProfiler::bucket_count_for(p0); - } - env.set_total_ticks(total_bucket_count); - } - - // Print constant table. - if (nm->consts_size() > 0) { - nm->print_nmethod_labels(env.output(), nm->consts_begin()); - int offset = 0; - for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) { - if ((offset % 8) == 0) { - env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p)); - } else { - env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p, offset, *((int32_t*) p)); - } - } - } - - env.decode_instructions(p, end); -} + if (_print_pc) { + st->print(" " PTR_FORMAT ": ", p); + } +} + +void decode_env::print_insn_bytes(address pc, address pc_limit) { + outputStream* st = output(); + size_t incr = 1; + size_t perline = _bytes_per_line; + if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int) + && !((uintptr_t)pc % sizeof(int)) + && !((uintptr_t)pc_limit % sizeof(int))) { + incr = sizeof(int); + if (perline % incr) perline += incr - (perline % incr); + } + while (pc < pc_limit) { + // tab to the desired column: + st->move_to(COMMENT_COLUMN); + address pc0 = pc; + address pc1 = pc + perline; + if (pc1 > pc_limit) pc1 = pc_limit; + for (; pc < pc1; pc += incr) { + if (pc == pc0) + st->print(BYTES_COMMENT); + else if ((uint)(pc - pc0) % sizeof(int) == 0) + st->print(" "); // put out a space on word boundaries + if (incr == sizeof(int)) + st->print("%08lx", *(int*)pc); + else st->print("%02x", (*pc)&0xFF); + } + st->cr(); + } +} + + +static void* event_to_env(void* env_pv, const char* event, void* arg) { + decode_env* env = (decode_env*) env_pv; + return env->handle_event(event, (address) arg); +} + +static int printf_to_env(void* env_pv, const char* format, ...) { + decode_env* env = (decode_env*) env_pv; + outputStream* st = env->output(); + size_t flen = strlen(format); + const char* raw = NULL; + if (flen == 0) return 0; + if (flen == 1 && format[0] == '\n') { st->bol(); return 1; } + if (flen < 2 || + strchr(format, '%') == NULL) { + raw = format; + } else if (format[0] == '%' && format[1] == '%' && + strchr(format+2, '%') == NULL) { + // happens a lot on machines with names like %foo + flen--; + raw = format+1; + } + if (raw != NULL) { + st->print_raw(raw, (int) flen); + return (int) flen; + } + va_list ap; + va_start(ap, format); + julong cnt0 = st->count(); + st->vprint(format, ap); + julong cnt1 = st->count(); + va_end(ap); + return (int)(cnt1 - cnt0); +} + +address decode_env::decode_instructions(address start, address end) { + _start = start; _end = end; + + assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr"); + + const int show_bytes = false; // for disassembler debugging + + //_version = Disassembler::pd_cpu_version(); + + if (!Disassembler::can_decode()) { + return NULL; + } + + // decode a series of instructions and return the end of the last instruction + + if (_print_raw) { + // Print whatever the library wants to print, w/o fancy callbacks. + // This is mainly for debugging the library itself. + FILE* out = stdout; + FILE* xmlout = (_print_raw > 1 ? out : NULL); + return use_new_version ? + (address) + (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end, + start, end - start, + NULL, (void*) xmlout, + NULL, (void*) out, + options(), 0/*nice new line*/) + : + (address) + (*Disassembler::_decode_instructions)(start, end, + NULL, (void*) xmlout, + NULL, (void*) out, + options()); + } + + return use_new_version ? + (address) + (*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end, + start, end - start, + &event_to_env, (void*) this, + &printf_to_env, (void*) this, + options(), 0/*nice new line*/) + : + (address) + (*Disassembler::_decode_instructions)(start, end, + &event_to_env, (void*) this, + &printf_to_env, (void*) this, + options()); +} + + +void Disassembler::decode(CodeBlob* cb, outputStream* st) { + if (!load_library()) return; + decode_env env(cb, st); + env.output()->print_cr("----------------------------------------------------------------------"); + env.output()->print_cr("%s at [" PTR_FORMAT ", " PTR_FORMAT "] %d bytes", cb->name(), cb->code_begin(), cb->code_end(), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*)); + env.decode_instructions(cb->code_begin(), cb->code_end()); +} + +void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) { + if (!load_library()) return; + decode_env env(CodeCache::find_blob_unsafe(start), st, c); + env.decode_instructions(start, end); +} + +void Disassembler::decode(nmethod* nm, outputStream* st) { + if (!load_library()) return; + decode_env env(nm, st); + env.output()->print_cr("----------------------------------------------------------------------"); + +#ifdef SHARK + SharkEntry* entry = (SharkEntry *) nm->code_begin(); + unsigned char* p = entry->code_start(); + unsigned char* end = entry->code_limit(); +#else + unsigned char* p = nm->code_begin(); + unsigned char* end = nm->code_end(); +#endif // SHARK + + nm->method()->method_holder()->name()->print_symbol_on(env.output()); + env.output()->print("."); + nm->method()->name()->print_symbol_on(env.output()); + env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] %d bytes", p, end, ((jlong)(end - p)) * sizeof(unsigned char*)); + + // If there has been profiling, print the buckets. + if (FlatProfiler::bucket_start_for(p) != NULL) { + unsigned char* p1 = p; + int total_bucket_count = 0; + while (p1 < end) { + unsigned char* p0 = p1; + p1 += pd_instruction_alignment(); + address bucket_pc = FlatProfiler::bucket_start_for(p1); + if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1) + total_bucket_count += FlatProfiler::bucket_count_for(p0); + } + env.set_total_ticks(total_bucket_count); + } + + // Print constant table. + if (nm->consts_size() > 0) { + nm->print_nmethod_labels(env.output(), nm->consts_begin()); + int offset = 0; + for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) { + if ((offset % 8) == 0) { + env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p)); + } else { + env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p, offset, *((int32_t*) p)); + } + } + } + + env.decode_instructions(p, end); +} diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -513,6 +513,8 @@ address dest = _constants->start() + CompilationResult_Site::pcOffset(patch); assert(!OopData::compressed(data), err_msg("unexpected compressed oop in data section")); _constants->relocate(dest, oop_Relocation::spec(oop_index)); + } else { + ShouldNotReachHere(); } } diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/graal/graalCompiler.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -32,6 +32,7 @@ #include "graal/graalRuntime.hpp" #include "runtime/arguments.hpp" #include "runtime/compilationPolicy.hpp" +#include "runtime/globals_extension.hpp" GraalCompiler* GraalCompiler::_instance = NULL; @@ -97,7 +98,12 @@ VMToCompiler::finalizeOptions(CITime || CITimeEach); if (UseCompiler) { - bool bootstrap = COMPILERGRAAL_PRESENT(BootstrapGraal) NOT_COMPILERGRAAL(false); + _external_deopt_i2c_entry = create_external_deopt_i2c(); +#ifdef COMPILERGRAAL + bool bootstrap = FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal; +#else + bool bootstrap = false; +#endif VMToCompiler::startCompiler(bootstrap); _initialized = true; CompilationPolicy::completed_vm_startup(); @@ -126,6 +132,34 @@ } } +address GraalCompiler::create_external_deopt_i2c() { + ResourceMark rm; + BufferBlob* buffer = BufferBlob::create("externalDeopt", 1*K); + CodeBuffer cb(buffer); + short buffer_locs[20]; + cb.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo)); + MacroAssembler masm(&cb); + + int total_args_passed = 5; + + BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); + VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); + int i = 0; + sig_bt[i++] = T_INT; + sig_bt[i++] = T_LONG; + sig_bt[i++] = T_VOID; // long stakes 2 slots + sig_bt[i++] = T_INT; + sig_bt[i++] = T_OBJECT; + + int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); + + SharedRuntime::gen_i2c_adapter(&masm, total_args_passed, comp_args_on_stack, sig_bt, regs); + masm.flush(); + + return AdapterBlob::create(&cb)->content_begin(); +} + + BufferBlob* GraalCompiler::initialize_buffer_blob() { JavaThread* THREAD = JavaThread::current(); BufferBlob* buffer_blob = THREAD->get_buffer_blob(); diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/graal/graalCompiler.hpp --- a/src/share/vm/graal/graalCompiler.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/graal/graalCompiler.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -35,7 +35,7 @@ bool _initialized; static GraalCompiler* _instance; - + address _external_deopt_i2c_entry; public: GraalCompiler(); @@ -67,9 +67,13 @@ void exit(); + address get_external_deopt_i2c_entry() {return _external_deopt_i2c_entry;} + static BasicType kindToBasicType(jchar ch); static BufferBlob* initialize_buffer_blob(); + + static address create_external_deopt_i2c(); }; // Tracing macros diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -329,13 +329,9 @@ return (jlong) (address) klass->implementor(); C2V_END -C2V_VMENTRY(void, initializeMethod,(JNIEnv *, jobject, jlong metaspace_method, jobject hotspot_method)) +C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, jlong metaspace_method)) methodHandle method = asMethod(metaspace_method); - InstanceKlass::cast(HotSpotResolvedJavaMethod::klass())->initialize(CHECK); - HotSpotResolvedJavaMethod::set_callerSensitive(hotspot_method, method->caller_sensitive()); - HotSpotResolvedJavaMethod::set_forceInline(hotspot_method, method->force_inline()); - HotSpotResolvedJavaMethod::set_dontInline(hotspot_method, method->dont_inline()); - HotSpotResolvedJavaMethod::set_ignoredBySecurityStackWalk(hotspot_method, method->is_ignored_by_security_stack_walk()); + return method->is_ignored_by_security_stack_walk(); C2V_END C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jlong metaspace_method)) @@ -805,7 +801,7 @@ {CC"findUniqueConcreteMethod", CC"("METASPACE_METHOD")"METASPACE_METHOD, FN_PTR(findUniqueConcreteMethod)}, {CC"getKlassImplementor", CC"("METASPACE_KLASS")"METASPACE_KLASS, FN_PTR(getKlassImplementor)}, {CC"getStackTraceElement", CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, - {CC"initializeMethod", CC"("METASPACE_METHOD HS_RESOLVED_METHOD")V", FN_PTR(initializeMethod)}, + {CC"methodIsIgnoredBySecurityStackWalk", CC"("METASPACE_METHOD")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, {CC"doNotInlineOrCompile", CC"("METASPACE_METHOD")V", FN_PTR(doNotInlineOrCompile)}, {CC"canInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(canInlineMethod)}, {CC"shouldInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(shouldInlineMethod)}, diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/graal/graalJavaAccess.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -55,10 +55,6 @@ oop_field(HotSpotResolvedJavaMethod, name, "Ljava/lang/String;") \ oop_field(HotSpotResolvedJavaMethod, holder, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;") \ long_field(HotSpotResolvedJavaMethod, metaspaceMethod) \ - boolean_field(HotSpotResolvedJavaMethod, callerSensitive) \ - boolean_field(HotSpotResolvedJavaMethod, forceInline) \ - boolean_field(HotSpotResolvedJavaMethod, dontInline) \ - boolean_field(HotSpotResolvedJavaMethod, ignoredBySecurityStackWalk) \ end_class \ start_class(HotSpotJavaType) \ oop_field(HotSpotJavaType, name, "Ljava/lang/String;") \ diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/graal/graalRuntime.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -438,13 +438,12 @@ return (jint)ret; JRT_END -JRT_ENTRY(void, GraalRuntime::vm_error(JavaThread* thread, oopDesc* where, oopDesc* format, jlong value)) +JRT_ENTRY(void, GraalRuntime::vm_error(JavaThread* thread, jlong where, jlong format, jlong value)) ResourceMark rm; - assert(where == NULL || java_lang_String::is_instance(where), "must be"); - const char *error_msg = where == NULL ? "" : java_lang_String::as_utf8_string(where); + const char *error_msg = where == 0L ? "" : (char*) (address) where; char *detail_msg = NULL; - if (format != NULL) { - const char* buf = java_lang_String::as_utf8_string(format); + if (format != 0L) { + const char* buf = (char*) (address) format; size_t detail_msg_length = strlen(buf) * 2; detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); jio_snprintf(detail_msg, detail_msg_length, buf, value); diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/graal/graalRuntime.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -43,7 +43,7 @@ static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); static void create_null_exception(JavaThread* thread); static void create_out_of_bounds_exception(JavaThread* thread, jint index); - static void vm_error(JavaThread* thread, oopDesc* where, oopDesc* format, jlong value); + static void vm_error(JavaThread* thread, jlong where, jlong format, jlong value); static oopDesc* load_and_clear_exception(JavaThread* thread); static void log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3); static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/oops/instanceKlass.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -3411,6 +3411,10 @@ ("purge: %s(%s): prev method @%d in version @%d is alive", method->name()->as_C_string(), method->signature()->as_C_string(), j, i)); + if (method->method_data() != NULL) { + // Clean out any weak method links + method->method_data()->clean_weak_method_links(); + } } } } @@ -3420,6 +3424,14 @@ ("purge: previous version stats: live=%d, deleted=%d", live_count, deleted_count)); } + + Array* methods = ik->methods(); + int num_methods = methods->length(); + for (int index2 = 0; index2 < num_methods; ++index2) { + if (methods->at(index2)->method_data() != NULL) { + methods->at(index2)->method_data()->clean_weak_method_links(); + } + } } // External interface for use during class unloading. diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/oops/method.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -108,12 +108,15 @@ #endif u2 _method_size; // size of this object u1 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) - u1 _jfr_towrite : 1, // Flags - _caller_sensitive : 1, - _force_inline : 1, - _hidden : 1, - _dont_inline : 1, - : 3; + // Flags + enum Flags { + _jfr_towrite = 1 << 0, + _caller_sensitive = 1 << 1, + _force_inline = 1 << 2, + _dont_inline = 1 << 3, + _hidden = 1 << 4 + }; + u1 _flags; #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) @@ -759,16 +762,41 @@ void init_intrinsic_id(); // updates from _none if a match static vmSymbols::SID klass_id_for_intrinsics(Klass* holder); - bool jfr_towrite() { return _jfr_towrite; } - void set_jfr_towrite(bool x) { _jfr_towrite = x; } - bool caller_sensitive() { return _caller_sensitive; } - void set_caller_sensitive(bool x) { _caller_sensitive = x; } - bool force_inline() { return _force_inline; } - void set_force_inline(bool x) { _force_inline = x; } - bool dont_inline() { return _dont_inline; } - void set_dont_inline(bool x) { _dont_inline = x; } - bool is_hidden() { return _hidden; } - void set_hidden(bool x) { _hidden = x; } + bool jfr_towrite() { + return (_flags & _jfr_towrite) != 0; + } + void set_jfr_towrite(bool x) { + _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite); + } + + bool caller_sensitive() { + return (_flags & _caller_sensitive) != 0; + } + void set_caller_sensitive(bool x) { + _flags = x ? (_flags | _caller_sensitive) : (_flags & ~_caller_sensitive); + } + + bool force_inline() { + return (_flags & _force_inline) != 0; + } + void set_force_inline(bool x) { + _flags = x ? (_flags | _force_inline) : (_flags & ~_force_inline); + } + + bool dont_inline() { + return (_flags & _dont_inline) != 0; + } + void set_dont_inline(bool x) { + _flags = x ? (_flags | _dont_inline) : (_flags & ~_dont_inline); + } + + bool is_hidden() { + return (_flags & _hidden) != 0; + } + void set_hidden(bool x) { + _flags = x ? (_flags | _hidden) : (_flags & ~_hidden); + } + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/oops/methodData.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -426,6 +426,16 @@ } } } + +void VirtualCallData::clean_weak_method_links() { + ReceiverTypeData::clean_weak_method_links(); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->on_stack()) { + clear_method_row(row); + } + } +} #endif // GRAAL #ifndef PRODUCT @@ -1693,3 +1703,85 @@ clean_extra_data(is_alive); verify_extra_data_clean(is_alive); } + +// Remove SpeculativeTrapData entries that reference a redefined +// method +void MethodData::clean_weak_method_extra_data() { + DataLayout* dp = extra_data_base(); + DataLayout* end = extra_data_limit(); + + int shift = 0; + for (; dp < end; dp = next_extra(dp)) { + switch(dp->tag()) { + case DataLayout::speculative_trap_data_tag: { + SpeculativeTrapData* data = new SpeculativeTrapData(dp); + Method* m = data->method(); + assert(m != NULL, "should have a method"); + if (!m->on_stack()) { + // "shift" accumulates the number of cells for dead + // SpeculativeTrapData entries that have been seen so + // far. Following entries must be shifted left by that many + // cells to remove the dead SpeculativeTrapData entries. + shift += (int)((intptr_t*)next_extra(dp) - (intptr_t*)dp); + } else { + // Shift this entry left if it follows dead + // SpeculativeTrapData entries + clean_extra_data_helper(dp, shift); + } + break; + } + case DataLayout::bit_data_tag: + // Shift this entry left if it follows dead SpeculativeTrapData + // entries + clean_extra_data_helper(dp, shift); + continue; + case DataLayout::no_tag: + case DataLayout::arg_info_data_tag: + // We are at end of the live trap entries. The previous "shift" + // cells contain entries that are either dead or were shifted + // left. They need to be reset to no_tag + clean_extra_data_helper(dp, shift, true); + return; + default: + fatal(err_msg("unexpected tag %d", dp->tag())); + } + } +} + +// Verify there's no redefined method referenced by a +// SpeculativeTrapData entry +void MethodData::verify_weak_method_extra_data_clean() { +#ifdef ASSERT + DataLayout* dp = extra_data_base(); + DataLayout* end = extra_data_limit(); + + for (; dp < end; dp = next_extra(dp)) { + switch(dp->tag()) { + case DataLayout::speculative_trap_data_tag: { + SpeculativeTrapData* data = new SpeculativeTrapData(dp); + Method* m = data->method(); + assert(m != NULL && m->on_stack(), "Method should exist"); + break; + } + case DataLayout::bit_data_tag: + continue; + case DataLayout::no_tag: + case DataLayout::arg_info_data_tag: + return; + default: + fatal(err_msg("unexpected tag %d", dp->tag())); + } + } +#endif +} + +void MethodData::clean_weak_method_links() { + for (ProfileData* data = first_data(); + is_valid(data); + data = next_data(data)) { + data->clean_weak_method_links(); + } + + clean_weak_method_extra_data(); + verify_weak_method_extra_data_clean(); +} diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/oops/methodData.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -257,6 +257,9 @@ // GC support void clean_weak_klass_links(BoolObjectClosure* cl); + + // Redefinition support + void clean_weak_method_links(); }; @@ -514,6 +517,9 @@ // GC support virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {} + // Redefinition support + virtual void clean_weak_method_links() {} + // CI translation: ProfileData can represent both MethodDataOop data // as well as CIMethodData data. This function is provided for translating // an oop in a ProfileData to the ci equivalent. Generally speaking, @@ -1429,6 +1435,9 @@ // GC support virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + + // Redefinition support + virtual void clean_weak_method_links(); #endif #ifndef PRODUCT @@ -2294,6 +2303,10 @@ void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false); void verify_extra_data_clean(BoolObjectClosure* is_alive); + // Redefinition support + void clean_weak_method_extra_data(); + void verify_weak_method_extra_data_clean(); + public: static int header_size() { return sizeof(MethodData)/wordSize; @@ -2572,6 +2585,8 @@ static bool profile_return_jsr292_only(); void clean_method_data(BoolObjectClosure* is_alive); + + void clean_weak_method_links(); }; #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/opto/node.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -476,6 +476,7 @@ #pragma clang diagnostic pop #endif + //------------------------------clone------------------------------------------ // Clone a Node. Node *Node::clone() const { diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/opto/runtime.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -1,6 +1,5 @@ /* * Copyright (c) 1998, 2013, 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 diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/globals_extension.hpp --- a/src/share/vm/runtime/globals_extension.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/globals_extension.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -86,6 +86,9 @@ #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_DIAGNOSTIC_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER) #endif +#ifdef GRAAL + GRAAL_FLAGS(GRAAL_DEVELOP_FLAG_MEMBER, GRAAL_PD_DEVELOP_FLAG_MEMBER, GRAAL_PRODUCT_FLAG_MEMBER, GRAAL_PD_PRODUCT_FLAG_MEMBER, GRAAL_NOTPRODUCT_FLAG_MEMBER) +#endif #ifdef COMPILER2 C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_EXPERIMENTAL_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER) #endif diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/javaCalls.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -40,11 +40,13 @@ #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" +#include "graal/graalJavaAccess.hpp" +#include "graal/graalCompiler.hpp" // ----------------------------------------------------- // Implementation of JavaCallWrapper -JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, Handle receiver, JavaValue* result, TRAPS) { +JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, JavaValue* result, TRAPS) { JavaThread* thread = (JavaThread *)THREAD; bool clear_pending_exception = true; @@ -75,10 +77,9 @@ // Make sure to set the oop's after the thread transition - since we can block there. No one is GC'ing // the JavaCallWrapper before the entry frame is on the stack. _callee_method = callee_method(); - _receiver = receiver(); #ifdef CHECK_UNHANDLED_OOPS - THREAD->allow_unhandled_oop(&_receiver); + // THREAD->allow_unhandled_oop(&_receiver); #endif // CHECK_UNHANDLED_OOPS _thread = (JavaThread *)thread; @@ -142,7 +143,6 @@ void JavaCallWrapper::oops_do(OopClosure* f) { - f->do_oop((oop*)&_receiver); handles()->oops_do(f); } @@ -335,14 +335,19 @@ CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) +#ifdef GRAAL + nmethod* nm = args->alternative_target(); + if (nm == NULL) { +#endif // Verify the arguments if (CheckJNICalls) { args->verify(method, result->get_type(), thread); } else debug_only(args->verify(method, result->get_type(), thread)); - -#ifndef GRAAL +#ifdef GRAAL + } +#else // Ignore call if method is empty if (method->is_empty_method()) { assert(result->get_type() == T_VOID, "an empty method must return a void value"); @@ -385,9 +390,6 @@ // the call to call_stub, the optimizer produces wrong code. intptr_t* result_val_address = (intptr_t*)(result->get_value_addr()); - // Find receiver - Handle receiver = (!method->is_static()) ? args->receiver() : Handle(); - // When we reenter Java, we need to reenable the yellow zone which // might already be disabled when we are in VM. if (thread->stack_yellow_zone_disabled()) { @@ -406,11 +408,15 @@ } #ifdef GRAAL - nmethod* nm = args->alternative_target(); if (nm != NULL) { if (nm->is_alive()) { ((JavaThread*) THREAD)->set_graal_alternate_call_target(nm->verified_entry_point()); + oop graalInstalledCode = nm->graal_installed_code(); + if (graalInstalledCode != NULL && HotSpotNmethod::isExternal(graalInstalledCode)) { + entry_point = GraalCompiler::instance()->get_external_deopt_i2c_entry(); + } else { entry_point = method->adapter()->get_i2c_entry(); + } } else { THROW(vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException()); } @@ -418,7 +424,7 @@ #endif // do call - { JavaCallWrapper link(method, receiver, result, CHECK); + { JavaCallWrapper link(method, result, CHECK); { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner StubRoutines::call_stub()( diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/javaCalls.hpp --- a/src/share/vm/runtime/javaCalls.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/javaCalls.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -57,7 +57,6 @@ JavaThread* _thread; // the thread to which this call belongs JNIHandleBlock* _handles; // the saved handle block Method* _callee_method; // to be able to collect arguments if entry frame is top frame - oop _receiver; // the receiver of the call (if a non-static call) JavaFrameAnchor _anchor; // last thread anchor state that we must restore @@ -65,7 +64,7 @@ public: // Construction/destruction - JavaCallWrapper(methodHandle callee_method, Handle receiver, JavaValue* result, TRAPS); + JavaCallWrapper(methodHandle callee_method, JavaValue* result, TRAPS); ~JavaCallWrapper(); // Accessors @@ -77,7 +76,6 @@ JavaValue* result() const { return _result; } // GC support Method* callee_method() { return _callee_method; } - oop receiver() { return _receiver; } void oops_do(OopClosure* f); bool is_first_frame() const { return _anchor.last_Java_sp() == NULL; } diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/mutexLocker.cpp --- a/src/share/vm/runtime/mutexLocker.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/mutexLocker.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -133,10 +133,6 @@ Mutex* JfrThreadGroups_lock = NULL; #endif -#ifdef GRAAL -Mutex* GraalDeoptLeafGraphIds_lock = NULL; -#endif // GRAAL - #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; static int _num_mutex; @@ -284,10 +280,6 @@ def(JfrStream_lock , Mutex, nonleaf+2, true); def(JfrStacktrace_lock , Mutex, special, true ); #endif - -#ifdef GRAAL - def(GraalDeoptLeafGraphIds_lock , Mutex, special, true); -#endif // GRAAL } GCMutexLocker::GCMutexLocker(Monitor * mutex) { diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/mutexLocker.hpp --- a/src/share/vm/runtime/mutexLocker.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/mutexLocker.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -149,10 +149,6 @@ extern Mutex* JfrThreadGroups_lock; // protects JFR access to Thread Groups #endif -#ifdef GRAAL -extern Mutex* GraalDeoptLeafGraphIds_lock; // protects access to the global array of deopt'ed leaf graphs -#endif // GRAAL - // A MutexLocker provides mutual exclusion with respect to a given mutex // for the scope which contains the locker. The lock is an OS lock, not // an object lock, and the two do not interoperate. Do not use Mutex-based diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/sharedRuntime.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -886,7 +886,10 @@ _implicit_null_throws++; #endif #ifdef GRAAL - if (nm->is_compiled_by_graal()) { + if (nm->is_compiled_by_graal() && nm->pc_desc_at(pc) != NULL) { + // If there's no PcDesc then we'll die way down inside of + // deopt instead of just getting normal error reporting, + // so only go there if it will succeed. target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check); } else { #endif @@ -1168,7 +1171,6 @@ assert(fr.is_entry_frame(), "must be"); // fr is now pointing to the entry frame. callee_method = methodHandle(THREAD, fr.entry_frame_call_wrapper()->callee_method()); - assert(fr.entry_frame_call_wrapper()->receiver() == NULL || !callee_method->is_static(), "non-null receiver for static call??"); } else { Bytecodes::Code bc; CallInfo callinfo; diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/thread.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -1445,6 +1445,8 @@ clear_must_deopt_id(); set_monitor_chunks(NULL); set_next(NULL); + set_gpu_exception_bci(0); + set_gpu_exception_method(NULL); set_thread_state(_thread_new); #if INCLUDE_NMT set_recorder(NULL); diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/thread.hpp Sun Mar 30 16:08:33 2014 +0200 @@ -946,6 +946,17 @@ volatile address _exception_handler_pc; // PC for handler of exception volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. + // Record the method and bci from a gpu kernel exception so + // it can be added into the exception stack trace + jint _gpu_exception_bci; + Method* _gpu_exception_method; + public: + void set_gpu_exception_bci(jint bci) { _gpu_exception_bci = bci; } + jint get_gpu_exception_bci() { return _gpu_exception_bci; } + void set_gpu_exception_method(Method* method) { _gpu_exception_method = method; } + Method* get_gpu_exception_method() { return _gpu_exception_method; } + + private: // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region diff -r 1617b1e25d31 -r 000c283d7b71 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Wed Mar 19 11:43:57 2014 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Sun Mar 30 16:08:33 2014 +0200 @@ -90,6 +90,7 @@ #include "runtime/deoptimization.hpp" #include "runtime/vframeArray.hpp" #include "runtime/globals.hpp" +#include "runtime/gpu.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/perfMemory.hpp" @@ -154,6 +155,9 @@ #ifdef TARGET_OS_ARCH_bsd_zero # include "vmStructs_bsd_zero.hpp" #endif + +#include "hsail/vm/vmStructs_hsail.hpp" + #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" @@ -374,6 +378,7 @@ nonstatic_field(Method, _vtable_index, int) \ nonstatic_field(Method, _method_size, u2) \ nonstatic_field(Method, _intrinsic_id, u1) \ + nonstatic_field(Method, _flags, u1) \ nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \ volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ @@ -2410,6 +2415,12 @@ /* ConstMethod anon-enum */ \ /********************************/ \ \ + declare_constant(Method::_jfr_towrite) \ + declare_constant(Method::_caller_sensitive) \ + declare_constant(Method::_force_inline) \ + declare_constant(Method::_dont_inline) \ + declare_constant(Method::_hidden) \ + \ declare_constant(ConstMethod::_has_linenumber_table) \ declare_constant(ConstMethod::_has_checked_exceptions) \ declare_constant(ConstMethod::_has_localvariable_table) \ @@ -2439,6 +2450,7 @@ declare_constant(DataLayout::call_type_data_tag) \ declare_constant(DataLayout::virtual_call_type_data_tag) \ declare_constant(DataLayout::parameters_type_data_tag) \ + declare_constant(DataLayout::speculative_trap_data_tag) \ \ /*************************************/ \ /* InstanceKlass enum */ \ @@ -3027,6 +3039,8 @@ GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_GPU_HSAIL(GENERATE_NONSTATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, @@ -3077,6 +3091,9 @@ GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_GPU_HSAIL(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_OS_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, @@ -3181,6 +3198,8 @@ CHECK_NO_OP, CHECK_NO_OP); + VM_STRUCTS_GPU_HSAIL(CHECK_NONSTATIC_VM_STRUCT_ENTRY); + VM_STRUCTS_OS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, @@ -3221,6 +3240,9 @@ CHECK_C2_VM_TYPE_ENTRY, CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); + VM_TYPES_GPU_HSAIL(CHECK_VM_TYPE_ENTRY, + CHECK_SINGLE_ARG_VM_TYPE_NO_OP); + VM_TYPES_OS_CPU(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP,