# HG changeset patch # User Tom Rodriguez # Date 1427131637 25200 # Node ID 3819bcdde8981da69bdda6042be51d4ebfb6936a # Parent 426e45c7577199b55ce2919f0fd1f3bb012018a5# Parent 220c494e50885d4dcb8250a2720b91ff6e470252 Merge diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Mon Mar 23 10:27:17 2015 -0700 @@ -88,7 +88,7 @@ @Override public String toString() { - return name + (isImmutable() ? ":immutable" : ":mutable"); + return name + (isImmutable() ? ":final" : ""); } /** diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Mon Mar 23 10:27:17 2015 -0700 @@ -1741,4 +1741,20 @@ public void casxa(Register rs1, Register rs2, Register rd, Asi asi) { ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi); } + + @Override + public InstructionCounter getInstructionCounter() { + return new SPARCInstructionCounter(this); + } + + public void patchAddImmediate(int position, int simm13) { + int inst = getInt(position); + assert SPARCAssembler.isSimm13(simm13) : simm13; + assert (inst >>> 30) == 0b10 : String.format("0x%x", inst); + assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst); + assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst); + inst = inst & (~((1 << 13) - 1)); + inst |= simm13 & ((1 << 12) - 1); + emitInt(inst, position); + } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCInstructionCounter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCInstructionCounter.java Mon Mar 23 10:27:17 2015 -0700 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.asm.sparc; + +import java.util.*; + +import com.oracle.graal.asm.Assembler.InstructionCounter; + +public class SPARCInstructionCounter implements InstructionCounter { + // Use a treemap to keep the order in the output + private static final TreeMap INSTRUCTION_MATCHER = new TreeMap<>(); + static { + // @formatter:off + INSTRUCTION_MATCHER.put("nop", new SPARCInstructionMatch(0xFFFF_FFFF, 0x0100_0000)); + INSTRUCTION_MATCHER.put("st", new OP3LowBitsMatcher(0b11, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf)); + INSTRUCTION_MATCHER.put("ld", new OP3LowBitsMatcher(0b11, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd)); + INSTRUCTION_MATCHER.put("all", new SPARCInstructionMatch(0x0, 0x0)); + // @formatter:on + } + private final SPARCAssembler asm; + + public SPARCInstructionCounter(SPARCAssembler asm) { + super(); + this.asm = asm; + } + + @Override + public int[] countInstructions(String[] instructionTypes, int beginPc, int endPc) { + SPARCInstructionMatch[] matchers = new SPARCInstructionMatch[instructionTypes.length]; + for (int i = 0; i < instructionTypes.length; i++) { + String typeName = instructionTypes[i]; + matchers[i] = INSTRUCTION_MATCHER.get(typeName); + if (matchers[i] == null) { + throw new IllegalArgumentException(String.format("Unknown instruction class %s, supported types are: %s", typeName, INSTRUCTION_MATCHER.keySet())); + } + } + return countBetween(matchers, beginPc, endPc); + } + + private int[] countBetween(SPARCInstructionMatch[] matchers, int startPc, int endPc) { + int[] counts = new int[matchers.length]; + for (int p = startPc; p < endPc; p += 4) { + int instr = asm.getInt(p); + for (int i = 0; i < matchers.length; i++) { + SPARCInstructionMatch matcher = matchers[i]; + if (matcher.matches(instr)) { + counts[i]++; + } + } + } + return counts; + } + + @Override + public String[] getSupportedInstructionTypes() { + return INSTRUCTION_MATCHER.keySet().toArray(new String[0]); + } + + /** + * Tests the lower 3 bits of the op3 field. + */ + private static class OP3LowBitsMatcher extends SPARCInstructionMatch { + private final int[] op3b03; + private final int op; + + public OP3LowBitsMatcher(int op, int... op3b03) { + super(0, 0); + this.op = op; + this.op3b03 = op3b03; + } + + @Override + public boolean matches(int instruction) { + if (instruction >>> 30 != op) { + return false; + } + int op3lo = (instruction >> 19) & ((1 << 4) - 1); + for (int op3Part : op3b03) { + if (op3Part == op3lo) { + return true; + } + } + return false; + } + } + + private static class SPARCInstructionMatch { + private final int mask; + private final int[] patterns; + + public SPARCInstructionMatch(int mask, int... patterns) { + super(); + this.mask = mask; + this.patterns = patterns; + } + + public boolean matches(int instruction) { + for (int pattern : patterns) { + if ((instruction & mask) == pattern) { + return true; + } + } + return false; + } + } +} diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java Mon Mar 23 10:27:17 2015 -0700 @@ -213,6 +213,10 @@ return hint; } + public InstructionCounter getInstructionCounter() { + throw new UnsupportedOperationException("Instruction counter is not implemented for " + this); + } + public static class LabelHint { private Label label; private int forPosition; @@ -242,4 +246,14 @@ return capturedTarget >= 0; } } + + /** + * Instruction counter class which gives the user of the assembler to count different kinds of + * instructions in the generated assembler code. + */ + public interface InstructionCounter { + String[] getSupportedInstructionTypes(); + + int[] countInstructions(String[] instructionTypes, int beginPc, int endPc); + } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon Mar 23 10:27:17 2015 -0700 @@ -320,7 +320,14 @@ throw Debug.handle(e); } FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig); - LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, graph.method(), stub); + String compilationUnitName; + ResolvedJavaMethod method = graph.method(); + if (method == null) { + compilationUnitName = ""; + } else { + compilationUnitName = method.format("%H.%n(%p)"); + } + LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, graph.method(), stub); LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes); NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Mon Mar 23 10:27:17 2015 -0700 @@ -78,7 +78,7 @@ public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes); - public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub); + public abstract LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub); public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Mon Mar 23 10:27:17 2015 -0700 @@ -335,8 +335,12 @@ @Override @SuppressWarnings("unchecked") - public A[] toArray(A[] template) { - return (A[]) Arrays.copyOf(nodes, size, template.getClass()); + public A[] toArray(A[] a) { + if (a.length >= size) { + System.arraycopy(nodes, 0, a, 0, size); + return a; + } + return (A[]) Arrays.copyOf(nodes, size, a.getClass()); } @Override diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon Mar 23 10:27:17 2015 -0700 @@ -78,8 +78,8 @@ } @Override - public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { - return new AMD64HotSpotLIRGenerationResult(lir, frameMapBuilder, stub); + public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { + return new AMD64HotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub); } @Override @@ -254,6 +254,9 @@ // Emit the suffix emitCodeSuffix(installedCodeOwner, crb, asm, frameMap); + + // Profile assembler instructions + profileInstructions(lir, crb); } /** diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java Mon Mar 23 10:27:17 2015 -0700 @@ -65,16 +65,16 @@ // load counters array masm.movptr(countersArrayReg, countersArrayAddr); - - forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment)); + CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(masm, countersArrayReg, increment, displacement); + forEachCounter(emitProcedure, target); // restore scratch register masm.movq(scratch, (AMD64Address) crb.asAddress(backupSlot)); } - private void emitIncrement(AMD64MacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) { + private static void emitIncrement(AMD64MacroAssembler masm, Register countersArrayReg, Value increment, int displacement) { // address for counter value - AMD64Address counterAddr = new AMD64Address(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment))); + AMD64Address counterAddr = new AMD64Address(countersArrayReg, displacement); // increment counter (in memory) if (isConstant(increment)) { masm.incrementl(counterAddr, asInt(asConstant(increment))); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java Mon Mar 23 10:27:17 2015 -0700 @@ -48,8 +48,8 @@ */ private Map calleeSaveInfo = CollectionsFactory.newMap(); - public AMD64HotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { - super(lir, frameMapBuilder); + public AMD64HotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { + super(compilationUnitName, lir, frameMapBuilder); this.stub = stub; } diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Mon Mar 23 10:27:17 2015 -0700 @@ -80,8 +80,8 @@ } @Override - public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { - return new SPARCHotSpotLIRGenerationResult(lir, frameMapBuilder, stub); + public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { + return new SPARCHotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub); } @Override @@ -247,6 +247,8 @@ crb.emit(lir); } while (i++ < 1); + profileInstructions(lir, crb); + HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); if (!frameContext.isStub) { diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java Mon Mar 23 10:27:17 2015 -0700 @@ -23,11 +23,14 @@ package com.oracle.graal.hotspot.sparc; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.sparc.SPARCAssembler.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.*; @@ -37,12 +40,16 @@ public class SPARCHotSpotCounterOp extends HotSpotCounterOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class); + private int[] counterPatchOffsets; + public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) { super(TYPE, name, group, increment, registers, config); + this.counterPatchOffsets = new int[1]; } public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) { super(TYPE, names, groups, increments, registers, config); + this.counterPatchOffsets = new int[names.length]; } @Override @@ -57,19 +64,17 @@ // load counters array masm.ldx(countersArrayAddr, countersArrayReg); - - forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment)); + IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm); + forEachCounter(emitter, target); } } - private void emitIncrement(SPARCMacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) { - // address for counter - SPARCAddress counterAddr = new SPARCAddress(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment))); - + private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) { try (ScratchRegister scratch = masm.getScratchRegister()) { Register counterReg = scratch.getRegister(); // load counter value masm.ldx(counterAddr, counterReg); + counterPatchOffsets[counterIndex] = masm.position(); // increment counter if (isConstant(increment)) { masm.add(counterReg, asInt(asConstant(increment)), counterReg); @@ -80,4 +85,53 @@ masm.stx(counterReg, counterAddr); } } + + /** + * Patches the increment value in the instruction emitted by the + * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is + * used if patching is needed after assembly. + * + * @param asm + * @param increment + */ + @Override + public void patchCounterIncrement(Assembler asm, int[] increment) { + for (int i = 0; i < increment.length; i++) { + int inst = counterPatchOffsets[i]; + ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]); + } + } + + public int[] getCounterPatchOffsets() { + return counterPatchOffsets; + } + + private class IncrementEmitter implements CounterProcedure { + private int lastDisplacement = 0; + private final Register countersArrayReg; + private final SPARCMacroAssembler masm; + + public IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) { + super(); + this.countersArrayReg = countersArrayReg; + this.masm = masm; + } + + public void apply(int counterIndex, Value increment, int displacement) { + SPARCAddress counterAddr; + int relativeDisplacement = displacement - lastDisplacement; + if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction + counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement); + } else { + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register tempOffsetRegister = scratch.getRegister(); + new Setx(relativeDisplacement, tempOffsetRegister, false).emit(masm); + masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg); + } + lastDisplacement = displacement; + counterAddr = new SPARCAddress(countersArrayReg, 0); + } + emitIncrement(counterIndex, masm, counterAddr, increment); + } + } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Mon Mar 23 10:27:17 2015 -0700 @@ -47,8 +47,8 @@ */ private Map calleeSaveInfo = new HashMap<>(); - public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { - super(lir, frameMapBuilder); + public SPARCHotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { + super(compilationUnitName, lir, frameMapBuilder); this.stub = stub; } @@ -67,5 +67,4 @@ Map getCalleeSaveInfo() { return calleeSaveInfo; } - } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Mon Mar 23 10:27:17 2015 -0700 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.test; -import static com.oracle.graal.nodes.spi.Replacements.*; - import java.io.*; import java.lang.reflect.*; import java.security.*; @@ -34,10 +32,16 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; +import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.*; +import com.oracle.graal.phases.*; /** * Tests the intrinsification of certain crypto methods. @@ -58,44 +62,51 @@ return installedCode; } - @Test - public void testEncryptSubstitution() throws Exception { - Assume.assumeTrue(SELF_RECURSIVE_INTRINSICS_ENABLED); + SecretKey aesKey; + SecretKey desKey; + byte[] input; + ByteArrayOutputStream aesExpected = new ByteArrayOutputStream(); + ByteArrayOutputStream desExpected = new ByteArrayOutputStream(); + public HotSpotCryptoSubstitutionTest() throws Exception { byte[] seed = {0x4, 0x7, 0x1, 0x1}; SecureRandom random = new SecureRandom(seed); KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES"); KeyGenerator desKeyGen = KeyGenerator.getInstance("DESede"); aesKeyGen.init(128, random); desKeyGen.init(168, random); - SecretKey aesKey = aesKeyGen.generateKey(); - SecretKey desKey = desKeyGen.generateKey(); - byte[] input = readClassfile16(getClass()); + aesKey = aesKeyGen.generateKey(); + desKey = desKeyGen.generateKey(); + input = readClassfile16(getClass()); + + aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); - ByteArrayOutputStream aesExpected = new ByteArrayOutputStream(); - aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); - aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding")); + desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding")); + } + @Test + public void testAESCryptIntrinsics() throws Exception { if (compileAndInstall("com.sun.crypto.provider.AESCrypt", "encryptBlock", "decryptBlock")) { ByteArrayOutputStream actual = new ByteArrayOutputStream(); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray()); } + } - ByteArrayOutputStream desExpected = new ByteArrayOutputStream(); - desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input)); - desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input)); - + @Test + public void testCipherBlockChainingIntrinsics() throws Exception { if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", "encrypt", "decrypt")) { ByteArrayOutputStream actual = new ByteArrayOutputStream(); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray()); actual.reset(); - actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input)); - actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input)); + actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding")); + actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding")); Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray()); } } @@ -114,9 +125,13 @@ Method method = lookup(className, methodName); if (method != null) { ResolvedJavaMethod installedCodeOwner = getMetaAccess().lookupJavaMethod(method); - StructuredGraph subst = getReplacements().getMethodSubstitution(installedCodeOwner); - if (subst != null) { - StructuredGraph graph = subst.copy(); + ResolvedJavaMethod substMethod = getReplacements().getMethodSubstitutionMethod(installedCodeOwner); + if (substMethod != null) { + StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES); + Plugins plugins = new Plugins(((HotSpotProviders) getProviders()).getGraphBuilderPlugins()); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, null, -2); + new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); Assert.assertNotNull(getCode(installedCodeOwner, graph, true)); atLeastOneCompiled = true; } else { @@ -191,7 +206,7 @@ return classFile; } - public byte[] runEncryptDecrypt(SecretKey key, String algorithm, byte[] input) throws Exception { + public byte[] runEncryptDecrypt(SecretKey key, String algorithm) throws Exception { byte[] indata = input.clone(); byte[] cipher = encrypt(indata, key, algorithm); byte[] plain = decrypt(cipher, key, algorithm); diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Mon Mar 23 10:27:17 2015 -0700 @@ -40,6 +40,7 @@ import com.oracle.graal.lir.LIRInstruction.OperandMode; import com.oracle.graal.lir.StandardOp.LabelOp; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; +import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.framemap.*; import com.oracle.graal.nodes.*; import com.oracle.graal.options.*; @@ -55,6 +56,9 @@ // @formatter:off @Option(help = "Use Graal stubs instead of HotSpot stubs where possible") public static final OptionValue PreferGraalStubs = new OptionValue<>(false); + @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + + " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) + public static final OptionValue ASMInstructionProfiling = new OptionValue<>(null); // @formatter:on } @@ -235,4 +239,10 @@ public DisassemblerProvider getDisassembler() { return getProviders().getDisassembler(); } + + protected void profileInstructions(LIR lir, CompilationResultBuilder crb) { + if (HotSpotBackend.Options.ASMInstructionProfiling.getValue() != null) { + HotSpotInstructionProfiling.countInstructions(lir, crb.asm); + } + } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java Mon Mar 23 10:27:17 2015 -0700 @@ -24,6 +24,8 @@ import static com.oracle.graal.api.code.ValueUtil.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; @@ -67,12 +69,42 @@ } protected interface CounterProcedure { - void apply(String name, String group, Value increment); + /** + * Lambda interface for iterating over counters declared in this op. + * + * @param counterIndex Index in this CounterOp object. + * @param increment Value for increment + * @param displacement Displacement in bytes in the counter array + */ + void apply(int counterIndex, Value increment, int displacement); } - protected void forEachCounter(CounterProcedure proc) { - for (int i = 0; i < names.length; i++) { - proc.apply(names[i], groups[i], increments[i]); + /** + * Calls the {@link CounterProcedure} for each counter in ascending order of their displacement + * in the counter array. + * + * @param proc The procedure to be called + * @param target Target architecture (used to calculate the array displacements) + */ + protected void forEachCounter(CounterProcedure proc, TargetDescription target) { + if (names.length == 1) { // fast path + int arrayIndex = getIndex(names[0], groups[0], increments[0]); + int displacement = getDisplacementForLongIndex(target, arrayIndex); + proc.apply(0, increments[0], displacement); + } else { // Slow path with sort by displacements ascending + int[] displacements = new int[names.length]; + HashMap offsetMap = new HashMap<>(names.length); + for (int i = 0; i < names.length; i++) { + int arrayIndex = getIndex(names[i], groups[i], increments[i]); + displacements[i] = getDisplacementForLongIndex(target, arrayIndex); + offsetMap.put(displacements[i], i); + } + Arrays.sort(displacements); + // Now apply in order + for (int offset : displacements) { + int idx = offsetMap.get(offset); + proc.apply(idx, increments[idx], displacements[idx]); + } } } @@ -86,6 +118,17 @@ return BenchmarkCounters.getIndex(name, group, config); } + /** + * Patches the increment value in the instruction emitted by this instruction. Use only, if + * patching is needed after assembly. + * + * @param asm + * @param increment + */ + public void patchCounterIncrement(Assembler asm, int[] increment) { + throw GraalInternalError.unimplemented(); + } + private static long asLong(JavaConstant value) { Kind kind = value.getKind(); switch (kind) { @@ -109,4 +152,11 @@ return (int) l; } + public String[] getNames() { + return names; + } + + public String[] getGroups() { + return groups; + } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java Mon Mar 23 10:27:17 2015 -0700 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.Assembler.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.phases.*; + +public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase { + public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER"; + private final String[] instructionsToProfile; + + public HotSpotInstructionProfiling(String instructionsToProfile) { + this.instructionsToProfile = instructionsToProfile.split(","); + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, + BenchmarkCounterFactory counterFactory) { + new Analyzer(lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), counterFactory).run(); + } + + private class Analyzer { + private final LIR lir; + private final BenchmarkCounterFactory counterFactory; + private final LIRInsertionBuffer buffer; + private final String compilationUnitName; + + public Analyzer(String compilationUnitName, LIR lir, BenchmarkCounterFactory counterFactory) { + this.lir = lir; + this.compilationUnitName = compilationUnitName; + this.counterFactory = counterFactory; + this.buffer = new LIRInsertionBuffer(); + } + + public void run() { + for (AbstractBlockBase block : lir.getControlFlowGraph().getBlocks()) { + doBlock(block); + } + } + + public void doBlock(AbstractBlockBase block) { + List instructions = lir.getLIRforBlock(block); + assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions; + assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1); + assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2); + assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0); + assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1); + String[] names = new String[instructionsToProfile.length]; + String[] groups = new String[instructionsToProfile.length]; + Value[] increments = new Value[instructionsToProfile.length]; + for (int i = 0; i < instructionsToProfile.length; i++) { + names[i] = compilationUnitName; + groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i]; + increments[i] = JavaConstant.INT_0; + } + HotSpotCounterOp op = (HotSpotCounterOp) counterFactory.createMultiBenchmarkCounter(names, groups, increments); + LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile); + assert inst != null; + buffer.init(instructions); + buffer.append(1, inst); + buffer.finish(); + } + } + + /** + * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)} + * calls this method for patching the instruction counts into the coutner increment code. + */ + public static void countInstructions(LIR lir, Assembler asm) { + InstructionCounterOp lastOp = null; + InstructionCounter counter = asm.getInstructionCounter(); + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + if (inst instanceof InstructionCounterOp) { + InstructionCounterOp currentOp = (InstructionCounterOp) inst; + + if (lastOp != null) { + int beginPc = lastOp.countOffsetEnd; + int endPc = currentOp.countOffsetBegin; + int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc); + lastOp.delegate.patchCounterIncrement(asm, instructionCounts); + } + lastOp = ((InstructionCounterOp) inst); + } + } + } + if (lastOp != null) { + assert lastOp.countOffsetBegin < asm.position(); + int beginPc = lastOp.countOffsetBegin; + int endPc = asm.position(); + int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc); + lastOp.delegate.patchCounterIncrement(asm, instructionCounts); + } + } + + public static class InstructionCounterOp extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(InstructionCounterOp.class); + private final HotSpotCounterOp delegate; + private final String[] instructionsToProfile; + private int countOffsetBegin; + private int countOffsetEnd; + + public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) { + super(TYPE); + this.delegate = delegate; + this.instructionsToProfile = instructionsToProfile; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + countOffsetBegin = crb.asm.position(); + this.delegate.emitCode(crb); + countOffsetEnd = crb.asm.position(); + } + + public String[] getInstructionsToProfile() { + return instructionsToProfile; + } + } +} diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Mon Mar 23 10:27:17 2015 -0700 @@ -30,6 +30,7 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.hotspot.word.*; import com.oracle.graal.nodes.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; @@ -48,6 +49,11 @@ } @Override + protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) { + return method.getAnnotation(HotSpotOperation.class) != null || super.hasGenericInvocationPluginAnnotation(method); + } + + @Override protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Executable originalMethod, Method substituteMethod) { final Class substituteClass = substituteMethod.getDeclaringClass(); if (substituteClass == IntegerSubstitutions.class || substituteClass == LongSubstitutions.class) { diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Mon Mar 23 10:27:17 2015 -0700 @@ -33,17 +33,14 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.options.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.replacements.SnippetTemplate.Arguments; /** * HotSpot implementation of {@link ConstantReflectionProvider}. */ -@SuppressWarnings("unused") public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified { private static final String SystemClassName = "Ljava/lang/System;"; @@ -317,7 +314,7 @@ ResolvedJavaMethod initMethod = null; try { Class rjm = ResolvedJavaMethod.class; - makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class)); + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class)); initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Mon Mar 23 10:27:17 2015 -0700 @@ -69,7 +69,7 @@ plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes)); plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection)); plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes)); - plugins.setInlineInvokePlugin(new HotSpotInlineInvokePlugin(nodeIntrinsification, replacements)); + plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements)); plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(nodeIntrinsification, wordOperationPlugin)); registerObjectPlugins(invocationPlugins); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Fri Mar 20 17:26:26 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +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.hotspot.meta; - -import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; -import static java.lang.String.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; -import com.oracle.graal.hotspot.word.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -public final class HotSpotInlineInvokePlugin implements InlineInvokePlugin { - private final ReplacementsImpl replacements; - private final NodeIntrinsificationPhase nodeIntrinsification; - - public HotSpotInlineInvokePlugin(NodeIntrinsificationPhase nodeIntrinsification, ReplacementsImpl replacements) { - this.nodeIntrinsification = nodeIntrinsification; - this.replacements = replacements; - } - - public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { - ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method); - if (subst != null) { - if (b.parsingReplacement() || InlineDuringParsing.getValue()) { - // Forced inlining of intrinsics - return new InlineInfo(subst, true, true); - } - } - if (b.parsingReplacement()) { - assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null && - !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); - - // Force inlining when parsing replacements - return new InlineInfo(method, true, true); - } else { - assert nodeIntrinsification.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(), - method.format("%h.%n"), b); - if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { - return new InlineInfo(method, false, false); - } - } - return null; - } - - public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { - if (b.parsingReplacement()) { - boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null; - Replacement replacement = b.getReplacement(); - assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"), - method.format("%h.%n(%p)")); - } - } -} diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Mon Mar 23 10:27:17 2015 -0700 @@ -132,7 +132,11 @@ } public LIRSuites createLIRSuites() { - return Suites.createDefaultLIRSuites(); + LIRSuites suites = Suites.createDefaultLIRSuites(); + String profileInstructions = HotSpotBackend.Options.ASMInstructionProfiling.getValue(); + if (profileInstructions != null) { + suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions)); + } + return suites; } - } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Mon Mar 23 10:27:17 2015 -0700 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.nodes.spi.Replacements.*; - import java.lang.reflect.*; import java.util.zip.*; @@ -64,9 +62,7 @@ replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class); - if (SELF_RECURSIVE_INTRINSICS_ENABLED) { - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); - } + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Mon Mar 23 10:27:17 2015 -0700 @@ -192,7 +192,7 @@ StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO); graph.disableInlinedMethodRecording(); - GraphKit kit = new GraphKit(graph, providers, wordTypes); + GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); ParameterNode[] params = createParameters(kit, args); ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Mon Mar 23 10:27:17 2015 -0700 @@ -29,9 +29,10 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; @@ -94,7 +95,8 @@ assert SnippetGraphUnderConstruction.get() == null; SnippetGraphUnderConstruction.set(graph); - new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, method).apply(graph); + ReplacementContext initialReplacementContext = new ReplacementContext(method, method); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); SnippetGraphUnderConstruction.set(null); graph.setGuardsStage(GuardsStage.FLOATING_GUARDS); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Mon Mar 23 10:27:17 2015 -0700 @@ -27,6 +27,7 @@ import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.HIRFrameStateBuilder.*; import java.util.*; @@ -42,6 +43,7 @@ import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; @@ -82,7 +84,7 @@ * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation * is a {@link MethodSubstitution} or a snippet. */ - static class ReplacementContext implements Replacement { + public static class ReplacementContext implements Replacement { /** * The method being replaced. */ @@ -121,6 +123,11 @@ IntrinsicContext asIntrinsic() { return null; } + + @Override + public String toString() { + return "Replacement{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + "}"; + } } /** @@ -129,25 +136,37 @@ * information required to build a frame state denoting the JVM state just before the * intrinsified call. */ - static class IntrinsicContext extends ReplacementContext { + public static class IntrinsicContext extends ReplacementContext { /** - * The arguments to the intrinsified invocation. + * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed. */ - private final ValueNode[] invokeArgs; + public static final int POST_PARSE_INLINE_BCI = -1; + + /** + * BCI denoting an intrinsic is the compilation root. + */ + public static final int ROOT_COMPILATION_BCI = -2; /** - * The BCI of the intrinsified invocation. + * The arguments to the intrinsic. */ - private final int invokeBci; + ValueNode[] args; - private FrameState invokeStateBefore; - private FrameState invokeStateDuring; + /** + * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or + * {@link #ROOT_COMPILATION_BCI}. + */ + final int bci; - public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] invokeArgs, int invokeBci) { + private FrameState stateBeforeCache; + + public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) { super(method, substitute); - this.invokeArgs = invokeArgs; - this.invokeBci = invokeBci; + assert bci != POST_PARSE_INLINE_BCI || args == null; + this.args = args; + this.bci = bci; + assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)"); } @Override @@ -155,34 +174,56 @@ return true; } - /** - * Gets the frame state that will restart the interpreter just before the intrinsified - * invocation. - */ - public FrameState getInvokeStateBefore(BytecodeParser parent) { - assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; - if (invokeStateDuring == null) { - assert invokeStateBefore == null; - // Find the ancestor calling the replaced method - BytecodeParser ancestor = parent; - while (ancestor.parsingReplacement()) { - ancestor = ancestor.getParent(); - } - invokeStateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); - invokeStateBefore = invokeStateDuring.duplicateModifiedBeforeCall(invokeBci, Kind.Void, invokeArgs); - } - return invokeStateBefore; + public boolean isPostParseInlined() { + return bci == POST_PARSE_INLINE_BCI; + } + + public boolean isCompilationRoot() { + return bci == ROOT_COMPILATION_BCI; } - public FrameState getInvokeStateDuring() { - assert invokeStateDuring != null : "must only be called after getInvokeStateBefore()"; - return invokeStateDuring; + public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) { + if (isCompilationRoot()) { + int maxLocals = method.getMaxLocals(); + // The 'args' were initialized based on the intrinsic method but a + // frame state's 'locals' needs to have the same length as the frame + // state method's 'max_locals'. + ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals); + ValueNode[] stack = EMPTY_ARRAY; + int stackSize = 0; + ValueNode[] locks = EMPTY_ARRAY; + List monitorIds = Collections.emptyList(); + return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false)); + } else if (isPostParseInlined()) { + return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); + } else { + assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; + if (stateBeforeCache == null) { + assert stateBeforeCache == null; + + // Find the non-intrinsic ancestor calling the intrinsified method + BytecodeParser ancestor = parent; + while (ancestor.parsingReplacement()) { + assert ancestor.replacementContext instanceof IntrinsicContext; + ancestor = ancestor.getParent(); + } + FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); + stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args); + } + return stateBeforeCache; + } } @Override IntrinsicContext asIntrinsic() { return this; } + + @Override + public String toString() { + return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + + (args == null ? "" : ", args: " + Arrays.toString(args)) + (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}"; + } } /** @@ -1104,214 +1145,214 @@ // Checkstyle: stop // @formatter:off - switch (opcode) { - case NOP : /* nothing to do */ break; - case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; - case ICONST_M1 : // fall through - case ICONST_0 : // fall through - case ICONST_1 : // fall through - case ICONST_2 : // fall through - case ICONST_3 : // fall through - case ICONST_4 : // fall through - case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; - case LCONST_0 : // fall through - case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; - case FCONST_0 : // fall through - case FCONST_1 : // fall through - case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; - case DCONST_0 : // fall through - case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; - case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; - case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; - 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_0 : // fall through - case ILOAD_1 : // fall through - case ILOAD_2 : // fall through - case ILOAD_3 : 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 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 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 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 IALOAD : genLoadIndexed(Kind.Int ); break; - case LALOAD : genLoadIndexed(Kind.Long ); break; - case FALOAD : genLoadIndexed(Kind.Float ); break; - case DALOAD : genLoadIndexed(Kind.Double); break; - case AALOAD : genLoadIndexed(Kind.Object); break; - case BALOAD : genLoadIndexed(Kind.Byte ); break; - case CALOAD : genLoadIndexed(Kind.Char ); break; - case SALOAD : genLoadIndexed(Kind.Short ); break; - case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; - case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; - case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; - case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; - case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; - case ISTORE_0 : // fall through - case ISTORE_1 : // fall through - case ISTORE_2 : // fall through - case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; - case LSTORE_0 : // fall through - case LSTORE_1 : // fall through - case LSTORE_2 : // fall through - case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; - case FSTORE_0 : // fall through - case FSTORE_1 : // fall through - case FSTORE_2 : // fall through - case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; - case DSTORE_0 : // fall through - case DSTORE_1 : // fall through - case DSTORE_2 : // fall through - case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; - case ASTORE_0 : // fall through - case ASTORE_1 : // fall through - case ASTORE_2 : // fall through - case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; - case IASTORE : genStoreIndexed(Kind.Int ); break; - case LASTORE : genStoreIndexed(Kind.Long ); break; - case FASTORE : genStoreIndexed(Kind.Float ); break; - case DASTORE : genStoreIndexed(Kind.Double); break; - case AASTORE : genStoreIndexed(Kind.Object); break; - case BASTORE : genStoreIndexed(Kind.Byte ); break; - case CASTORE : genStoreIndexed(Kind.Char ); break; - case SASTORE : genStoreIndexed(Kind.Short ); break; - case POP : frameState.xpop(); break; - case POP2 : frameState.xpop(); frameState.xpop(); break; - case DUP : frameState.xpush(frameState.xpeek()); break; - case DUP_X1 : // fall through - case DUP_X2 : // fall through - case DUP2 : // fall through - case DUP2_X1 : // fall through - case DUP2_X2 : // fall through - case SWAP : stackOp(opcode); break; - case IADD : // fall through - case ISUB : // fall through - case IMUL : genArithmeticOp(Kind.Int, opcode); break; - case IDIV : // fall through - case IREM : genIntegerDivOp(Kind.Int, opcode); break; - case LADD : // fall through - case LSUB : // fall through - case LMUL : genArithmeticOp(Kind.Long, opcode); break; - case LDIV : // fall through - case LREM : genIntegerDivOp(Kind.Long, opcode); break; - case FADD : // fall through - case FSUB : // fall through - case FMUL : // fall through - case FDIV : // fall through - case FREM : genArithmeticOp(Kind.Float, opcode); break; - case DADD : // fall through - case DSUB : // fall through - case DMUL : // fall through - case DDIV : // fall through - case DREM : genArithmeticOp(Kind.Double, opcode); break; - case INEG : genNegateOp(Kind.Int); break; - case LNEG : genNegateOp(Kind.Long); break; - case FNEG : genNegateOp(Kind.Float); break; - case DNEG : genNegateOp(Kind.Double); break; - case ISHL : // fall through - case ISHR : // fall through - case IUSHR : genShiftOp(Kind.Int, opcode); break; - case IAND : // fall through - case IOR : // fall through - case IXOR : genLogicOp(Kind.Int, opcode); break; - case LSHL : // fall through - case LSHR : // fall through - case LUSHR : genShiftOp(Kind.Long, opcode); break; - case LAND : // fall through - case LOR : // fall through - case LXOR : genLogicOp(Kind.Long, opcode); break; - case IINC : genIncrement(); break; - case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; - case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; - case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; - case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; - case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; - case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; - case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; - case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; - case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; - case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; - case L2I : genNarrow(Kind.Long, Kind.Int); break; - case I2L : genSignExtend(Kind.Int, Kind.Long); break; - case I2B : genSignExtend(Kind.Byte, Kind.Int); break; - case I2S : genSignExtend(Kind.Short, Kind.Int); break; - case I2C : genZeroExtend(Kind.Char, Kind.Int); break; - case LCMP : genCompareOp(Kind.Long, false); break; - case FCMPL : genCompareOp(Kind.Float, true); break; - case FCMPG : genCompareOp(Kind.Float, false); break; - case DCMPL : genCompareOp(Kind.Double, true); break; - case DCMPG : genCompareOp(Kind.Double, false); break; - case IFEQ : genIfZero(Condition.EQ); break; - case IFNE : genIfZero(Condition.NE); break; - case IFLT : genIfZero(Condition.LT); break; - case IFGE : genIfZero(Condition.GE); break; - case IFGT : genIfZero(Condition.GT); break; - case IFLE : genIfZero(Condition.LE); break; - case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; - case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; - case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; - case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; - case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; - case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; - case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; - case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; - case GOTO : genGoto(); break; - case JSR : genJsr(stream.readBranchDest()); break; - case RET : genRet(stream.readLocalIndex()); break; - case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; - case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; - case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; - case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; - case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; - case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; - case ARETURN : genReturn(frameState.apop(), Kind.Object); break; - case RETURN : genReturn(null, Kind.Void); 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; - case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; - case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; - case NEW : genNewInstance(stream.readCPI()); break; - case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; - case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; - case ARRAYLENGTH : genArrayLength(); break; - case ATHROW : genThrow(); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; - case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; - case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; - case IFNULL : genIfNull(Condition.EQ); break; - case IFNONNULL : genIfNull(Condition.NE); break; - case GOTO_W : genGoto(); break; - case JSR_W : genJsr(stream.readBranchDest()); break; - case BREAKPOINT: - throw new BailoutException("concurrent setting of breakpoint"); - default: - throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); - } - // @formatter:on + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; + case ICONST_M1 : // fall through + case ICONST_0 : // fall through + case ICONST_1 : // fall through + case ICONST_2 : // fall through + case ICONST_3 : // fall through + case ICONST_4 : // fall through + case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; + case LCONST_0 : // fall through + case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; + case FCONST_0 : // fall through + case FCONST_1 : // fall through + case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; + case DCONST_0 : // fall through + case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; + case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; + 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_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : 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 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 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 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 IALOAD : genLoadIndexed(Kind.Int ); break; + case LALOAD : genLoadIndexed(Kind.Long ); break; + case FALOAD : genLoadIndexed(Kind.Float ); break; + case DALOAD : genLoadIndexed(Kind.Double); break; + case AALOAD : genLoadIndexed(Kind.Object); break; + case BALOAD : genLoadIndexed(Kind.Byte ); break; + case CALOAD : genLoadIndexed(Kind.Char ); break; + case SALOAD : genLoadIndexed(Kind.Short ); break; + case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(Kind.Int ); break; + case LASTORE : genStoreIndexed(Kind.Long ); break; + case FASTORE : genStoreIndexed(Kind.Float ); break; + case DASTORE : genStoreIndexed(Kind.Double); break; + case AASTORE : genStoreIndexed(Kind.Object); break; + case BASTORE : genStoreIndexed(Kind.Byte ); break; + case CASTORE : genStoreIndexed(Kind.Char ); break; + case SASTORE : genStoreIndexed(Kind.Short ); break; + case POP : frameState.xpop(); break; + case POP2 : frameState.xpop(); frameState.xpop(); break; + case DUP : frameState.xpush(frameState.xpeek()); break; + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(Kind.Int, opcode); break; + case IDIV : // fall through + case IREM : genIntegerDivOp(Kind.Int, opcode); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(Kind.Long, opcode); break; + case LDIV : // fall through + case LREM : genIntegerDivOp(Kind.Long, opcode); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(Kind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(Kind.Double, opcode); break; + case INEG : genNegateOp(Kind.Int); break; + case LNEG : genNegateOp(Kind.Long); break; + case FNEG : genNegateOp(Kind.Float); break; + case DNEG : genNegateOp(Kind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(Kind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(Kind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(Kind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(Kind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; + case L2I : genNarrow(Kind.Long, Kind.Int); break; + case I2L : genSignExtend(Kind.Int, Kind.Long); break; + case I2B : genSignExtend(Kind.Byte, Kind.Int); break; + case I2S : genSignExtend(Kind.Short, Kind.Int); break; + case I2C : genZeroExtend(Kind.Char, Kind.Int); break; + case LCMP : genCompareOp(Kind.Long, false); break; + case FCMPL : genCompareOp(Kind.Float, true); break; + case FCMPG : genCompareOp(Kind.Float, false); break; + case DCMPL : genCompareOp(Kind.Double, true); break; + case DCMPG : genCompareOp(Kind.Double, false); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; + case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; + case GOTO : genGoto(); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; + case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; + case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; + case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; + case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; + case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; + case ARETURN : genReturn(frameState.apop(), Kind.Object); break; + case RETURN : genReturn(null, Kind.Void); 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; + case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(); break; + case JSR_W : genJsr(stream.readBranchDest()); break; + case BREAKPOINT: + throw new BailoutException("concurrent setting of breakpoint"); + default: + throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); + } + // @formatter:on // Checkstyle: resume } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java Mon Mar 23 10:27:17 2015 -0700 @@ -51,6 +51,15 @@ * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract) */ public String disassemble(ResolvedJavaMethod method) { + return disassemble(method, 0, Integer.MAX_VALUE); + } + + /** + * Disassembles the bytecode of a given method in a {@code javap}-like format. + * + * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract) + */ + public String disassemble(ResolvedJavaMethod method, int startBci, int endBci) { if (method.getCode() == null) { return null; } @@ -60,10 +69,11 @@ int opcode = stream.currentBC(); while (opcode != Bytecodes.END) { int bci = stream.currentBCI(); - String mnemonic = Bytecodes.nameOf(opcode); - buf.append(String.format("%4d: %-14s", bci, mnemonic)); - if (stream.nextBCI() > bci + 1) { - // @formatter:off + if (bci >= startBci && bci <= endBci) { + String mnemonic = Bytecodes.nameOf(opcode); + buf.append(String.format("%4d: %-14s", bci, mnemonic)); + if (stream.nextBCI() > bci + 1) { + // @formatter:off switch (opcode) { case BIPUSH : buf.append(stream.readByte()); break; case SIPUSH : buf.append(stream.readShort()); break; @@ -211,8 +221,9 @@ } } // @formatter:on + } + buf.append(String.format("%n")); } - buf.append(String.format("%n")); stream.next(); opcode = stream.currentBC(); } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon Mar 23 10:27:17 2015 -0700 @@ -100,7 +100,9 @@ * Furthermore, if it is non-null and not equal to {@link #rootMethod} then this is the * original method for which a snippet exists (e.g., System.arraycopy()). */ - private final ResolvedJavaMethod rootMethodIsReplacement; + // private final ResolvedJavaMethod rootMethodIsReplacement; + + private final ReplacementContext initialReplacementContext; private final GraphBuilderConfiguration graphBuilderConfig; private final OptimisticOptimizations optimisticOpts; @@ -109,20 +111,21 @@ private final SnippetReflectionProvider snippetReflectionProvider; public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) { + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; this.metaAccess = metaAccess; this.stampProvider = stampProvider; this.constantReflection = constantReflection; this.snippetReflectionProvider = snippetReflectionProvider; - this.rootMethodIsReplacement = rootMethodIsReplacement; + this.initialReplacementContext = initialReplacementContext; + assert metaAccess != null; } public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) { - this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement); + OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) { + this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); } @Override @@ -134,10 +137,10 @@ this.currentGraph = graph; TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); try { - ReplacementContext replacementContext = rootMethodIsReplacement != null ? new ReplacementContext(rootMethodIsReplacement, rootMethod) : null; + ReplacementContext replacementContext = initialReplacementContext; BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, replacementContext); HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph); - frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || rootMethodIsReplacement != null, graphBuilderConfig.getPlugins().getParameterPlugin()); + frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); parser.build(graph.start(), frameState); parser.connectLoopEndToBegin(); @@ -1316,13 +1319,30 @@ } ReplacementContext context = this.replacementContext; if (context != null && context.isCallToOriginal(targetMethod)) { - assert context.asIntrinsic() == null : "intrinsic cannot call the method it is intrinsifying"; - // Self recursive replacement means the original - // method should be called. - if (context.method.hasBytecodes()) { - parseAndInlineCallee(context.method, args, null); + IntrinsicContext intrinsic = context.asIntrinsic(); + if (intrinsic != null) { + if (intrinsic.isCompilationRoot()) { + // A root compiled intrinsic needs to deoptimize + // if the slow path is taken + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); + deopt.setStateBefore(intrinsic.getInvokeStateBefore(currentGraph, null)); + return true; + } else { + // Otherwise inline the original method. Any frame state created + // during the inlining will exclude frame(s) in the + // intrinsic method (see HIRFrameStateBuilder.create(int bci)). + parseAndInlineCallee(context.method, args, null); + return true; + } } else { - return false; + // Self recursive replacement means the original + // method should be called. + if (context.method.hasBytecodes()) { + parseAndInlineCallee(context.method, args, null); + return true; + } else { + return false; + } } } else { if (context == null && inlineInfo.isReplacement) { @@ -2451,7 +2471,8 @@ if (bp != this) { fmt.format("%n%s", indent); } - fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bci(), bp.parsingReplacement()); + fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingReplacement()); + fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.method, bp.bci(), bp.bci() + 10)); bp = bp.parent; indent += " "; } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Mon Mar 23 10:27:17 2015 -0700 @@ -43,8 +43,8 @@ public final class HIRFrameStateBuilder { - private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; - private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; + static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; protected final BytecodeParser parser; protected final ResolvedJavaMethod method; @@ -145,6 +145,14 @@ javaIndex += kind.getSlotCount(); index++; } + + if (parser.replacementContext instanceof IntrinsicContext) { + IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext; + if (intrinsic.isCompilationRoot()) { + // Records the parameters to an root compiled intrinsic + intrinsic.args = locals.clone(); + } + } } private HIRFrameStateBuilder(HIRFrameStateBuilder other) { @@ -200,28 +208,20 @@ if (parser.parsingReplacement()) { IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); if (intrinsic != null) { - assert parent != null : "intrinsics can only be processed in context of a caller"; - - // We're somewhere in an intrinsic. In this case, we want a frame state - // that will restart the interpreter just before the intrinsified - // invocation. - return intrinsic.getInvokeStateBefore(parent); + return intrinsic.getInvokeStateBefore(parser.getGraph(), parent); } } + // If this is the recursive call in a partial intrinsification + // the frame(s) of the intrinsic method are omitted + while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) { + parent = parent.getParent(); + } return create(bci, parent, false); } public FrameState create(int bci, BytecodeParser parent, boolean duringCall) { if (outerFrameState == null && parent != null) { outerFrameState = parent.getFrameState().create(parent.bci()); - if (parser.parsingReplacement()) { - IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); - if (intrinsic != null) { - // A side-effect of creating the frame state in a replacing - // parent is that the 'during' frame state is created as well - outerFrameState = intrinsic.getInvokeStateDuring(); - } - } } if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Mon Mar 23 10:27:17 2015 -0700 @@ -35,7 +35,7 @@ } public static double test(double arg) throws NaN { - double v = Math.sin(arg); + double v = Math.sin(arg) * Math.sin(arg * 5); if (Double.isNaN(v)) { // NaN can't be tested against itself throw new NaN(); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java Mon Mar 23 10:27:17 2015 -0700 @@ -56,4 +56,6 @@ boolean hasForeignCall(); void setForeignCall(boolean b); + + String getCompilationUnitName(); } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java Mon Mar 23 10:27:17 2015 -0700 @@ -34,10 +34,15 @@ * Records whether the code being generated makes at least one foreign call. */ private boolean hasForeignCall; + /** + * Human readable name of this compilation unit. + */ + private final String compilationUnitName; - public LIRGenerationResultBase(LIR lir, FrameMapBuilder frameMapBuilder) { + public LIRGenerationResultBase(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder) { this.lir = lir; this.frameMapBuilder = frameMapBuilder; + this.compilationUnitName = compilationUnitName; } public LIR getLIR() { @@ -69,4 +74,8 @@ assert frameMap != null : "getFrameMap() can only be used after calling buildFrameMap()!"; return frameMap; } + + public String getCompilationUnitName() { + return compilationUnitName; + } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java Mon Mar 23 10:27:17 2015 -0700 @@ -136,12 +136,13 @@ } String[] groups = new String[names.size()]; Arrays.fill(groups, "Move Operations"); - - LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0])); - assert inst != null; - buffer.init(instructions); - buffer.append(1, inst); - buffer.finish(); + if (names.size() > 0) { // Don't pollute LIR when nothing has to be done + LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0])); + assert inst != null; + buffer.init(instructions); + buffer.append(1, inst); + buffer.finish(); + } } } diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -37,7 +37,7 @@ /** * The {@code ConstantNode} represents a {@link Constant constant}. */ -@NodeInfo(shortName = "Const", nameTemplate = "Const({p#rawvalue})") +@NodeInfo(nameTemplate = "C({p#rawvalue})") public final class ConstantNode extends FloatingNode implements LIRLowerable { public static final NodeClass TYPE = NodeClass.create(ConstantNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -25,7 +25,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -@NodeInfo(allowedUsageTypes = {InputType.Association}) +@NodeInfo(allowedUsageTypes = {InputType.Association}, nameTemplate = "End") public final class EndNode extends AbstractEndNode { public static final NodeClass TYPE = NodeClass.create(EndNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Mar 23 10:27:17 2015 -0700 @@ -40,7 +40,7 @@ * * This can be used as debug or deoptimization information. */ -@NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}") +@NodeInfo(nameTemplate = "@{p#method/s}:{p#bci}") public final class FrameState extends VirtualState implements IterableNodeType { public static final NodeClass TYPE = NodeClass.create(FrameState.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -28,7 +28,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; -@NodeInfo(allowedUsageTypes = {InputType.Guard}) +@NodeInfo(allowedUsageTypes = {InputType.Guard}, nameTemplate = "Proxy({i#value})") public final class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(GuardProxyNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -31,7 +31,7 @@ /** * Memory {@code PhiNode}s merge memory dependencies at control flow merges. */ -@NodeInfo(nameTemplate = "MemoryPhi({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory}) +@NodeInfo(nameTemplate = "Φ({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory}) public final class MemoryPhiNode extends PhiNode implements MemoryNode { public static final NodeClass TYPE = NodeClass.create(MemoryPhiNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -31,7 +31,7 @@ /** * The {@code Parameter} instruction is a placeholder for an incoming argument to a function call. */ -@NodeInfo(nameTemplate = "Param({p#index})") +@NodeInfo(nameTemplate = "P({p#index})") public final class ParameterNode extends AbstractLocalNode implements IterableNodeType, UncheckedInterfaceProvider { public static final NodeClass TYPE = NodeClass.create(ParameterNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -30,7 +30,7 @@ /** * The start node of a graph. */ -@NodeInfo(allowedUsageTypes = {InputType.Memory}) +@NodeInfo(allowedUsageTypes = {InputType.Memory}, nameTemplate = "Start") public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint.Single { public static final NodeClass TYPE = NodeClass.create(StartNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -30,7 +30,7 @@ /** * Value {@link PhiNode}s merge data flow values at control flow merges. */ -@NodeInfo(nameTemplate = "ValuePhi({i#values})") +@NodeInfo(nameTemplate = "Φ({i#values})") public class ValuePhiNode extends PhiNode { public static final NodeClass TYPE = NodeClass.create(ValuePhiNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -27,7 +27,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.spi.*; -@NodeInfo +@NodeInfo(nameTemplate = "Proxy({i#value})") public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy { public static final NodeClass TYPE = NodeClass.create(ValueProxyNode.class); diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -36,7 +36,7 @@ * Location node that is the sum of two other location nodes. Can represent locations in the form of * [(base + x) + y] where base is a node and x and y are location nodes. */ -@NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}") +@NodeInfo(nameTemplate = "&+({p#locationIdentity/s})") public final class AddLocationNode extends LocationNode implements Canonicalizable.Binary { public static final NodeClass TYPE = NodeClass.create(AddLocationNode.class); diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -33,7 +33,7 @@ * Location node that has a constant displacement. Can represent addresses of the form [base + disp] * where base is a node and disp is a constant. */ -@NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}") +@NodeInfo(nameTemplate = "&({p#locationIdentity/s})") public final class ConstantLocationNode extends LocationNode { public static final NodeClass TYPE = NodeClass.create(ConstantLocationNode.class); diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -37,7 +37,7 @@ * [base + index * scale + disp] where base and index are nodes and scale and disp are integer * constants. */ -@NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}") +@NodeInfo(nameTemplate = "&({p#locationIdentity/s})[{i#index}]") public final class IndexedLocationNode extends LocationNode implements Canonicalizable { public static final NodeClass TYPE = NodeClass.create(IndexedLocationNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Mon Mar 23 10:27:17 2015 -0700 @@ -37,7 +37,7 @@ /** * The {@code LoadFieldNode} represents a read of a static or instance field. */ -@NodeInfo(nameTemplate = "LoadField#{p#field/s}") +@NodeInfo(nameTemplate = "#{p#field/s}") public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable.Unary, VirtualizableRoot, UncheckedInterfaceProvider { public static final NodeClass TYPE = NodeClass.create(LoadFieldNode.class); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Mon Mar 23 10:27:17 2015 -0700 @@ -33,8 +33,6 @@ * Interface for managing replacements. */ public interface Replacements { - // Disabled until bug in support for this is fixed. - boolean SELF_RECURSIVE_INTRINSICS_ENABLED = false; /** * Gets the snippet graph derived from a given method. diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon Mar 23 10:27:17 2015 -0700 @@ -32,6 +32,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; @@ -432,14 +433,18 @@ frameState.replaceAndDelete(stateAfterException); } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { handleMissingAfterExceptionFrameState(frameState); + } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { + // This is an intrinsic. Deoptimizing within an intrinsic + // must re-execute the intrinsified invocation + assert frameState.outerFrameState() == null; + NodeInputList invokeArgsList = invoke.callTarget().arguments(); + ValueNode[] invokeArgs = invokeArgsList.isEmpty() ? NO_ARGS : invokeArgsList.toArray(new ValueNode[invokeArgsList.size()]); + FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, invokeArgs); + frameState.replaceAndDelete(stateBeforeCall); } else { // only handle the outermost frame states if (frameState.outerFrameState() == null) { - assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; - assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; - assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; - assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; - assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()) : frameState; + assert checkInlineeFrameState(invoke, inlineGraph, frameState); if (outerFrameState == null) { outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind); } @@ -450,6 +455,32 @@ } } + static boolean checkInlineeFrameState(Invoke invoke, StructuredGraph inlineGraph, FrameState frameState) { + assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; + assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; + assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; + assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; + if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) { + if (frameState.method().equals(inlineGraph.method())) { + // Normal inlining expects all outermost inlinee frame states to + // denote the inlinee method + } else if (frameState.method().equals(invoke.callTarget().targetMethod())) { + // This occurs when an intrinsic calls back to the original + // method to handle a slow path. During parsing of such a + // partial intrinsic, these calls are given frame states + // that exclude the outer frame state denoting a position + // in the intrinsic code. + assert inlineGraph.method().getAnnotation(MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " + + frameState; + } else { + throw new AssertionError(frameState.toString()); + } + } + return true; + } + + private static final ValueNode[] NO_ARGS = {}; + private static boolean isStateAfterException(FrameState frameState) { return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized()); } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Mon Mar 23 10:27:17 2015 -0700 @@ -50,7 +50,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Mon Mar 23 10:27:17 2015 -0700 @@ -36,7 +36,6 @@ import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.word.*; import com.oracle.graal.word.nodes.*; @@ -55,11 +54,9 @@ installer = (ReplacementsImpl) getProviders().getReplacements(); } - private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); - @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Mon Mar 23 10:27:17 2015 -0700 @@ -24,14 +24,25 @@ import org.junit.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.runtime.*; public class ReplacementsParseTest extends GraalCompilerTest { + private static final Object THROW_EXCEPTION_MARKER = new Object() { + @Override + public String toString() { + return "THROW_EXCEPTION_MARKER"; + } + }; + static class TestMethods { static double next(double v) { return Math.nextAfter(v, 1.0); @@ -45,6 +56,14 @@ return Math.nextAfter(x, d); } + static String stringize(Object obj) { + String res = String.valueOf(obj); + if (res.equals(THROW_EXCEPTION_MARKER.toString())) { + // Tests exception throwing from partial intrinsification + throw new RuntimeException("ex: " + obj); + } + return res; + } } @ClassSubstitution(TestMethods.class) @@ -55,6 +74,23 @@ double xx = (x == -0.0 ? 0.0 : x); return Math.nextAfter(xx, d); } + + @MethodSubstitution + static String stringize(Object obj) { + if (obj != null && obj.getClass() == String.class) { + return asNonNullString(obj); + } else { + return stringize(obj); + } + } + + public static String asNonNullString(Object object) { + return asNonNullStringIntrinsic(object, String.class, true, true); + } + + @NodeIntrinsic(PiNode.class) + private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull); + } private static boolean substitutionsInstalled; @@ -112,4 +148,23 @@ outArray[i] = TestMethods.nextAfter(inArray[i], direction); } } + + @Test + public void testCallStringize() { + test("callStringize", "a string"); + test("callStringize", THROW_EXCEPTION_MARKER); + test("callStringize", Boolean.TRUE); + } + + public Object callStringize(Object obj) { + return TestMethods.stringize(obj); + } + + @Test + public void testRootCompileStringize() { + ResolvedJavaMethod method = getResolvedJavaMethod(TestMethods.class, "stringize"); + test(method, null, "a string"); + test(method, null, Boolean.TRUE); + test(method, null, THROW_EXCEPTION_MARKER); + } } diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon Mar 23 10:27:17 2015 -0700 @@ -45,7 +45,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Mon Mar 23 10:27:17 2015 -0700 @@ -32,141 +32,109 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; -import com.oracle.graal.word.*; public class BoxingSnippets implements Snippets { - /** - * This snippet inlining policy differs from the default one in that it does normal inlining of - * boxing methods like {@link Integer#valueOf(int)} (as opposed to method substitution). - */ - public static class BoxingSnippetInliningPolicy implements SnippetInliningPolicy { - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (method.isNative()) { - return false; - } - if (method.getAnnotation(Fold.class) != null) { - return false; - } - if (method.getAnnotation(NodeIntrinsic.class) != null) { - return false; - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - return true; - } - - @Override - public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { - return false; - } - } - - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object booleanValueOf(boolean value) { valueOfCounter.inc(); return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object byteValueOf(byte value) { valueOfCounter.inc(); return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object charValueOf(char value) { valueOfCounter.inc(); return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object doubleValueOf(double value) { valueOfCounter.inc(); return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object floatValueOf(float value) { valueOfCounter.inc(); return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object intValueOf(int value) { valueOfCounter.inc(); return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object longValueOf(long value) { valueOfCounter.inc(); return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object shortValueOf(short value) { valueOfCounter.inc(); return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static boolean booleanValue(Boolean value) { valueOfCounter.inc(); return value.booleanValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static byte byteValue(Byte value) { valueOfCounter.inc(); return value.byteValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static char charValue(Character value) { valueOfCounter.inc(); return value.charValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static double doubleValue(Double value) { valueOfCounter.inc(); return value.doubleValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static float floatValue(Float value) { valueOfCounter.inc(); return value.floatValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static int intValue(Integer value) { valueOfCounter.inc(); return value.intValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static long longValue(Long value) { valueOfCounter.inc(); return value.longValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static short shortValue(Short value) { valueOfCounter.inc(); return value.shortValue(); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Mon Mar 23 10:27:17 2015 -0700 @@ -0,0 +1,52 @@ +/* + * 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.replacements; + +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.nodes.*; + +public final class DefaultInlineInvokePlugin implements InlineInvokePlugin { + private final ReplacementsImpl replacements; + + public DefaultInlineInvokePlugin(ReplacementsImpl replacements) { + this.replacements = replacements; + } + + public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { + InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType); + if (inlineInfo == null) { + if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { + return new InlineInfo(method, false, false); + } + } + return inlineInfo; + } + + public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { + replacements.notifyOfNoninlinedInvoke(b, method, invoke); + } +} diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Mon Mar 23 10:27:17 2015 -0700 @@ -28,16 +28,21 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.calc.*; 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.common.DeadCodeEliminationPhase.Optionality; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; /** @@ -50,6 +55,7 @@ protected final Providers providers; protected final StructuredGraph graph; protected final WordTypes wordTypes; + protected final GraphBuilderConfiguration.Plugins graphBuilderPlugins; protected FixedWithNextNode lastFixedNode; private final List structures; @@ -57,10 +63,11 @@ abstract static class Structure { } - public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes) { + public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes, GraphBuilderConfiguration.Plugins graphBuilderPlugins) { this.providers = providers; this.graph = graph; this.wordTypes = wordTypes; + this.graphBuilderPlugins = graphBuilderPlugins; this.lastFixedNode = graph.start(); structures = new ArrayList<>(); @@ -202,14 +209,28 @@ } /** - * Inlines a given invocation to a method. The graph of the inlined method is - * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and - * method substitutions. + * Inlines a given invocation to a method. The graph of the inlined method is processed in the + * same manner as for snippets and method substitutions. */ public void inline(InvokeNode invoke) { ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); - ReplacementsImpl replacements = (ReplacementsImpl) providers.getReplacements(); - StructuredGraph calleeGraph = replacements.makeGraph(method, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + + MetaAccessProvider metaAccess = providers.getMetaAccess(); + Plugins plugins = new Plugins(graphBuilderPlugins); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + + StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO); + IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph); + + // Remove all frame states from inlinee + for (Node node : calleeGraph.getNodes()) { + if (node instanceof StateSplit) { + ((StateSplit) node).setStateAfter(null); + } + } + new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph); + InliningUtil.inline(invoke, calleeGraph, false, null); } diff -r 426e45c75771 -r 3819bcdde898 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 Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon Mar 23 10:27:17 2015 -0700 @@ -25,7 +25,9 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.compiler.GraalCompiler.*; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; +import static java.lang.String.*; import java.lang.reflect.*; import java.util.*; @@ -41,10 +43,14 @@ import com.oracle.graal.compiler.common.*; 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.NodeIntrinsic; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; -import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; +import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; +import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.*; import com.oracle.graal.java.GraphBuilderPhase.Instance; import com.oracle.graal.nodes.*; @@ -53,13 +59,11 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; +import com.oracle.graal.word.*; -public class ReplacementsImpl implements Replacements { +public class ReplacementsImpl implements Replacements, InlineInvokePlugin { public final Providers providers; public final SnippetReflectionProvider snippetReflection; @@ -77,6 +81,56 @@ this.graphBuilderPlugins = plugins; } + protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) { + return nodeIntrinsificationPhase.getIntrinsic(method) != null || method.getAnnotation(Word.Operation.class) != null || nodeIntrinsificationPhase.isFoldable(method); + } + + private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough + + /** + * Determines whether a given method should be inlined based on whether it has a substitution or + * whether the inlining context is already within a substitution. + * + * @return an {@link InlineInfo} object specifying how {@code method} is to be inlined or null + * if it should not be inlined based on substitution related criteria + */ + public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { + ResolvedJavaMethod subst = getMethodSubstitutionMethod(method); + if (subst != null) { + if (b.parsingReplacement() || InlineDuringParsing.getValue()) { + // Forced inlining of intrinsics + return new InlineInfo(subst, true, true); + } + return null; + } + if (b.parsingReplacement()) { + assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); + + assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; + + if (method.getName().startsWith("$jacoco")) { + throw new GraalInternalError("Found call to JaCoCo instrumentation method " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " + + b.getMethod().getDeclaringClass().getSourceFileName() + " should fix this."); + } + + // Force inlining when parsing replacements + return new InlineInfo(method, true, true); + } else { + assert nodeIntrinsificationPhase.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(), + method.format("%h.%n"), b); + } + return null; + } + + public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { + if (b.parsingReplacement()) { + boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null; + Replacement replacement = b.getReplacement(); + assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"), + method.format("%h.%n(%p)")); + } + } + /** * Encapsulates method and macro substitutions for a single class. */ @@ -273,7 +327,7 @@ try (DebugCloseable a = SnippetPreparationTime.start()) { FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal : FrameStateProcessing.CollapseFrameForSingleSideEffect; - StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, inliningPolicy(method), frameStateProcessing); + StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing); Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount()); if (!UseSnippetGraphCache || args != null) { return newGraph; @@ -313,7 +367,7 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graph = makeGraph(substitute, null, original, inliningPolicy(substitute), FrameStateProcessing.None); + graph = makeGraph(substitute, null, original, FrameStateProcessing.None); graph.freeze(); graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); @@ -424,26 +478,6 @@ return originalJavaMethod; } - private static SnippetInliningPolicy createPolicyClassInstance(Class policyClass) { - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - public SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class policyClass = SnippetInliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(providers.getMetaAccess()); - } - return createPolicyClassInstance(policyClass); - } - /** * Creates a preprocessed graph for a snippet or method substitution. * @@ -451,11 +485,10 @@ * @param args * @param original the original method if {@code method} is a {@linkplain MethodSubstitution * substitution} otherwise null - * @param policy the inlining policy to use during preprocessing * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled. */ - public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) { - return createGraphMaker(method, original, frameStateProcessing).makeGraph(args, policy); + public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { + return createGraphMaker(method, original, frameStateProcessing).makeGraph(args); } /** @@ -527,9 +560,9 @@ this.frameStateProcessing = frameStateProcessing; } - public StructuredGraph makeGraph(Object[] args, final SnippetInliningPolicy policy) { + public StructuredGraph makeGraph(Object[] args) { try (Scope s = Debug.scope("BuildSnippetGraph", method)) { - StructuredGraph graph = parseGraph(method, args, policy, 0); + StructuredGraph graph = parseGraph(method, args); if (args == null) { // Cannot have a finalized version of a graph in the cache @@ -603,14 +636,12 @@ return false; } - private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough - - private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) { + private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args) { StructuredGraph graph = args == null ? replacements.graphCache.get(methodToParse) : null; if (graph == null) { StructuredGraph newGraph = null; try (Scope s = Debug.scope("ParseGraph", methodToParse)) { - newGraph = buildGraph(methodToParse, args, policy == null ? replacements.inliningPolicy(methodToParse) : policy, inliningDepth); + newGraph = buildGraph(methodToParse, args); } catch (Throwable e) { throw Debug.handle(e); } @@ -662,8 +693,17 @@ protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { - ResolvedJavaMethod rootMethodIsReplacement = substitutedMethod == null ? method : substitutedMethod; - return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement); + ReplacementContext initialReplacementContext = null; + if (method.getAnnotation(MethodSubstitution.class) != null) { + // Late inlined intrinsic + initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1); + } else { + // Snippet + assert method.getAnnotation(Snippet.class) != null; + ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; + initialReplacementContext = new ReplacementContext(original, method); + } + return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); } /** @@ -700,67 +740,10 @@ } } - private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) { - assert inliningDepth < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; + private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args) { assert methodToParse.hasBytecodes() : methodToParse; final StructuredGraph graph = buildInitialGraph(methodToParse, args); try (Scope s = Debug.scope("buildGraph", graph)) { - Set doNotInline = null; - for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) { - if (doNotInline != null && doNotInline.contains(callTarget)) { - continue; - } - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (substitutedMethod != null && (callee.equals(method) || callee.equals(substitutedMethod))) { - /* - * Ensure that calls to the original method inside of a substitution ends up - * calling it instead of the Graal substitution. - */ - if (substitutedMethod.hasBytecodes()) { - final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod, null); - Mark mark = graph.getMark(); - InliningUtil.inline(callTarget.invoke(), originalGraph, true, null); - for (MethodCallTargetNode inlinedCallTarget : graph.getNewNodes(mark).filter(MethodCallTargetNode.class)) { - if (doNotInline == null) { - doNotInline = new HashSet<>(); - } - // We do not want to do further inlining (now) for calls - // in the original method as this can cause unlimited - // recursive inlining given an eager inlining policy such - // as DefaultSnippetInliningPolicy. - doNotInline.add(inlinedCallTarget); - } - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, originalGraph, null); - } - } else { - Class macroNodeClass = InliningUtil.getMacroNodeClass(replacements, callee); - if (macroNodeClass != null) { - InliningUtil.inlineMacroNode(callTarget.invoke(), callee, macroNodeClass); - } else { - StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(replacements, callee); - if (callTarget.invokeKind().isDirect() && (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) { - StructuredGraph targetGraph; - if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) { - targetGraph = intrinsicGraph; - } else { - if (callee.getName().startsWith("$jacoco")) { - throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + callee.format("%H.%n(%p)") + " from " + methodToParse.format("%H.%n(%p)") + - " while preparing replacement " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " + - methodToParse.getDeclaringClass().getSourceFileName() + " should fix this."); - } - targetGraph = parseGraph(callee, null, policy, inliningDepth + 1); - } - Object beforeInlineData = beforeInline(callTarget, targetGraph); - InliningUtil.inline(callTarget.invoke(), targetGraph, true, null); - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, targetGraph, beforeInlineData); - } - } - } - } - - afterInlining(graph); for (LoopEndNode end : graph.getNodes(LoopEndNode.TYPE)) { end.disableSafepoint(); diff -r 426e45c75771 -r 3819bcdde898 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Fri Mar 20 17:26:26 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Mon Mar 23 10:27:17 2015 -0700 @@ -24,11 +24,7 @@ import java.lang.annotation.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.word.*; /** * A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering @@ -39,12 +35,6 @@ public @interface Snippet { /** - * Specifies the class defining the inlining policy for this snippet. A - * {@linkplain DefaultSnippetInliningPolicy default} policy is used if none is supplied. - */ - Class inlining() default SnippetInliningPolicy.class; - - /** * Specifies whether all FrameStates within this snippet should always be removed. If this is * false, FrameStates are only removed if there are no side-effecting instructions in the * snippet. @@ -52,70 +42,6 @@ boolean removeAllFrameStates() default false; /** - * Guides inlining decisions used when installing a snippet. - */ - public interface SnippetInliningPolicy { - - /** - * Determines if {@code method} should be inlined into {@code caller}. - */ - boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); - - /** - * Determines if {@code method} should be inlined using its replacement graph. - * - * @return true if the replacement graph should be used, false for normal inlining. - */ - boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse); - } - - /** - * The default inlining policy which inlines everything except for methods in any of the - * following categories. - *
    - *
  • {@linkplain Fold foldable} methods
  • - *
  • {@linkplain NodeIntrinsic node intrinsics}
  • - *
  • native methods
  • - *
  • constructors of {@link Throwable} classes
  • - *
- */ - public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { - - private final MetaAccessProvider metaAccess; - - public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess) { - this.metaAccess = metaAccess; - } - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (method.isNative()) { - return false; - } - if (method.getAnnotation(Fold.class) != null) { - return false; - } - if (method.getAnnotation(NodeIntrinsic.class) != null) { - return false; - } - if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { - if (method.isConstructor()) { - return false; - } - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - return true; - } - - @Override - public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { - return true; - } - } - - /** * Denotes a snippet parameter representing 0 or more arguments that will be bound during * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet * template creation, its value must be an array whose length specifies the number of arguments diff -r 426e45c75771 -r 3819bcdde898 mx/mx_graal.py --- a/mx/mx_graal.py Fri Mar 20 17:26:26 2015 -0700 +++ b/mx/mx_graal.py Mon Mar 23 10:27:17 2015 -0700 @@ -1425,18 +1425,29 @@ mx.log('TOTAL TIME: ' + '[' + str(allDuration) + ']') class Task: + # None or a list of strings. If not None, only tasks whose title + # matches at least one of the substrings in this list will return + # a non-None value from __enter__. The body of a 'with Task(...) as t' + # statement should check 't' and exit immediately if it is None. + filters = None + def __init__(self, title, tasks=None): - self.start = time.time() + self.tasks = tasks self.title = title - self.end = None - self.duration = None - self.tasks = tasks - mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title) + self.skipped = Task.filters is not None and not any([f in title for f in Task.filters]) + if not self.skipped: + self.start = time.time() + self.end = None + self.duration = None + mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title) def __enter__(self): assert self.tasks is not None, "using Task with 'with' statement requires to pass the tasks list in the constructor" + if self.skipped: + return None return self def __exit__(self, exc_type, exc_value, traceback): - self.tasks.append(self.stop()) + if not self.skipped: + self.tasks.append(self.stop()) def stop(self): self.end = time.time() self.duration = datetime.timedelta(seconds=self.end - self.start) @@ -1481,63 +1492,65 @@ def _basic_gate_body(args, tasks): # Build server-hosted-graal now so we can run the unit tests - with Task('BuildHotSpotGraalHosted: product', tasks): - buildvms(['--vms', 'server', '--builds', 'product']) + with Task('BuildHotSpotGraalHosted: product', tasks) as t: + if t: buildvms(['--vms', 'server', '--builds', 'product']) # Run unit tests on server-hosted-graal with VM('server', 'product'): - with Task('UnitTests:hosted-product', tasks): - unittest(['--enable-timing', '--verbose', '--fail-fast']) + with Task('UnitTests:hosted-product', tasks) as t: + if t: unittest(['--enable-timing', '--verbose', '--fail-fast']) # Build the other VM flavors - with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks): - buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product']) + with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks) as t: + if t: buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product']) with VM('graal', 'fastdebug'): - with Task('BootstrapWithSystemAssertions:fastdebug', tasks): - vm(['-esa', '-XX:-TieredCompilation', '-version']) + with Task('BootstrapWithSystemAssertions:fastdebug', tasks) as t: + if t: vm(['-esa', '-XX:-TieredCompilation', '-version']) with VM('graal', 'fastdebug'): - with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks): - vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version']) + with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks) as t: + if t: vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version']) with VM('graal', 'fastdebug'): - with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks): - vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version']) + with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks) as t: + if t: vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version']) with VM('graal', 'product'): - with Task('BootstrapWithGCVerification:product', tasks): - out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write - vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) + with Task('BootstrapWithGCVerification:product', tasks) as t: + if t: + out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write + vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) with VM('graal', 'product'): - with Task('BootstrapWithG1GCVerification:product', tasks): - out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write - vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) + with Task('BootstrapWithG1GCVerification:product', tasks) as t: + if t: + out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write + vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) with VM('graal', 'product'): - with Task('BootstrapWithRegisterPressure:product', tasks): - vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version']) + with Task('BootstrapWithRegisterPressure:product', tasks) as t: + if t: vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version']) with VM('graal', 'product'): - with Task('BootstrapWithImmutableCode:product', tasks): - vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version']) + with Task('BootstrapWithImmutableCode:product', tasks) as t: + if t: vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version']) for vmbuild in ['fastdebug', 'product']: for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): with Task(str(test) + ':' + vmbuild, tasks) as t: - if not test.test('graal'): + if t and not test.test('graal'): t.abort(test.name + ' Failed') # ensure -Xbatch still works with VM('graal', 'product'): - with Task('DaCapo_pmd:BatchMode:product', tasks): - dacapo(['-Xbatch', 'pmd']) + with Task('DaCapo_pmd:BatchMode:product', tasks) as t: + if t: dacapo(['-Xbatch', 'pmd']) # ensure -Xcomp still works with VM('graal', 'product'): - with Task('XCompMode:product', tasks): - vm(['-Xcomp', '-version']) + with Task('XCompMode:product', tasks) as t: + if t: vm(['-Xcomp', '-version']) if args.jacocout is not None: jacocoreport([args.jacocout]) @@ -1545,17 +1558,19 @@ global _jacoco _jacoco = 'off' - with Task('CleanAndBuildIdealGraphVisualizer', tasks): - env = _igvFallbackJDK(os.environ) - buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')) - mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env) + with Task('CleanAndBuildIdealGraphVisualizer', tasks) as t: + if t: + env = _igvFallbackJDK(os.environ) + buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')) + mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env) # Prevent Graal modifications from breaking the standard builds if args.buildNonGraal: - with Task('BuildHotSpotVarieties', tasks): - buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product']) - if mx.get_os() not in ['windows', 'cygwin']: - buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized']) + with Task('BuildHotSpotVarieties', tasks) as t: + if t: + buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product']) + if mx.get_os() not in ['windows', 'cygwin']: + buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized']) for vmbuild in ['product', 'fastdebug']: for theVm in ['client', 'server']: @@ -1563,11 +1578,11 @@ mx.log('The' + theVm + ' VM is not supported on this platform') continue with VM(theVm, vmbuild): - with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks): - dacapo(['pmd']) + with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks) as t: + if t: dacapo(['pmd']) - with Task('UnitTests:' + theVm + ':' + vmbuild, tasks): - unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api']) + with Task('UnitTests:' + theVm + ':' + vmbuild, tasks) as t: + if t: unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api']) def gate(args, gate_body=_basic_gate_body): @@ -1580,61 +1595,67 @@ parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code') parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code') parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM') + parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run') parser.add_argument('--jacocout', help='specify the output directory for jacoco report') args = parser.parse_args(args) global _jacoco + if args.task_filter: + Task.filters = args.task_filter.split(',') tasks = [] total = Task('Gate') try: - with Task('Pylint', tasks): - mx.pylint([]) + with Task('Pylint', tasks) as t: + if t: mx.pylint([]) def _clean(name='Clean'): - with Task(name, tasks): - cleanArgs = [] - if not args.cleanNative: - cleanArgs.append('--no-native') - if not args.cleanJava: - cleanArgs.append('--no-java') - clean(cleanArgs) + with Task(name, tasks) as t: + if t: + cleanArgs = [] + if not args.cleanNative: + cleanArgs.append('--no-native') + if not args.cleanJava: + cleanArgs.append('--no-java') + clean(cleanArgs) _clean() with Task('IDEConfigCheck', tasks): - mx.ideclean([]) - mx.ideinit([]) + if t: + mx.ideclean([]) + mx.ideinit([]) eclipse_exe = mx.get_env('ECLIPSE_EXE') if eclipse_exe is not None: with Task('CodeFormatCheck', tasks) as t: - if mx.eclipseformat(['-e', eclipse_exe]) != 0: + if t and mx.eclipseformat(['-e', eclipse_exe]) != 0: t.abort('Formatter modified files - run "mx eclipseformat", check in changes and repush') with Task('Canonicalization Check', tasks) as t: - mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...')) - if mx.canonicalizeprojects([]) != 0: - t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.') + if t: + mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...')) + if mx.canonicalizeprojects([]) != 0: + t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.') if mx.get_env('JDT'): with Task('BuildJavaWithEcj', tasks): - build(['-p', '--no-native', '--jdt-warning-as-error']) + if t: build(['-p', '--no-native', '--jdt-warning-as-error']) _clean('CleanAfterEcjBuild') with Task('BuildJavaWithJavac', tasks): - build(['-p', '--no-native', '--force-javac']) + if t: build(['-p', '--no-native', '--force-javac']) with Task('Checkstyle', tasks) as t: - if mx.checkstyle([]) != 0: + if t and mx.checkstyle([]) != 0: t.abort('Checkstyle warnings were found') with Task('Checkheaders', tasks) as t: - if checkheaders([]) != 0: + if t and checkheaders([]) != 0: t.abort('Checkheaders warnings were found') with Task('FindBugs', tasks) as t: - if findbugs([]) != 0: + if t and findbugs([]) != 0: t.abort('FindBugs warnings were found') if exists('jacoco.exec'): @@ -1663,6 +1684,9 @@ mx.log(' =======') mx.log(' ' + str(total.duration)) + if args.task_filter: + Task.filters = None + def deoptalot(args): """bootstrap a fastdebug Graal VM with DeoptimizeALot and VerifyOops on diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java Mon Mar 23 10:27:17 2015 -0700 @@ -86,7 +86,7 @@ this.to = to; this.state = State.SAME; this.label = label; - this.type = type; + this.type = type.intern(); } static WeakHashMap> immutableCache = new WeakHashMap<>(); diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Mon Mar 23 10:27:17 2015 -0700 @@ -271,7 +271,7 @@ } else { sb.append(", "); } - sb.append(p[0] + "=" + p[1]); + sb.append(p[0]).append("=").append(p[1]); } return sb.append("]").toString(); } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Mon Mar 23 10:27:17 2015 -0700 @@ -706,7 +706,8 @@ private void parseNodes(InputGraph graph) throws IOException { int count = readInt(); Map props = new HashMap<>(); - List edges = new LinkedList<>(); + List inputEdges = new ArrayList<>(count); + List succEdges = new ArrayList<>(count); for (int i = 0; i < count; i++) { int id = readInt(); InputNode node = new InputNode(id); @@ -733,7 +734,7 @@ props.put(key, value); } } - int edgesStart = edges.size(); + ArrayList currentEdges = new ArrayList<>(); int portNum = 0; for (TypedPort p : nodeClass.inputs) { if (p.isList) { @@ -741,14 +742,18 @@ for (int j = 0; j < size; j++) { int in = readInt(); if (in >= 0) { - edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true)); + Edge e = new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true); + currentEdges.add(e); + inputEdges.add(e); portNum++; } } } else { int in = readInt(); if (in >= 0) { - edges.add(new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true)); + Edge e = new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true); + currentEdges.add(e); + inputEdges.add(e); portNum++; } } @@ -761,19 +766,23 @@ for (int j = 0; j < size; j++) { int sux = readInt(); if (sux >= 0) { - edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false)); + Edge e = new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false); + currentEdges.add(e); + succEdges.add(e); portNum++; } } } else { int sux = readInt(); if (sux >= 0) { - edges.add(new Edge(id, sux, (char) portNum, p.name, "Successor", false)); + Edge e = new Edge(id, sux, (char) portNum, p.name, "Successor", false); + currentEdges.add(e); + succEdges.add(e); portNum++; } } } - properties.setProperty("name", createName(edges.subList(edgesStart, edges.size()), props, nodeClass.nameTemplate)); + properties.setProperty("name", createName(currentEdges, props, nodeClass.nameTemplate)); properties.setProperty("class", nodeClass.className); switch (nodeClass.className) { case "BeginNode": @@ -786,9 +795,20 @@ graph.addNode(node); props.clear(); } - for (Edge e : edges) { - char fromIndex = e.input ? 1 : e.num; - char toIndex = e.input ? e.num : 0; + + Set nodesWithSuccessor = new HashSet<>(); + + for (Edge e : succEdges) { + assert !e.input; + char fromIndex = e.num; + nodesWithSuccessor.add(graph.getNode(e.from)); + char toIndex = 0; + graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type)); + } + for (Edge e : inputEdges) { + assert e.input; + char fromIndex = (char) (nodesWithSuccessor.contains(graph.getNode(e.from)) ? 1 : 0); + char toIndex = e.num; graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type)); } } @@ -805,7 +825,7 @@ case "i": StringBuilder inputString = new StringBuilder(); for(Edge edge : edges) { - if (name.equals(edge.label)) { + if (edge.label.startsWith(name) && (name.length() == edge.label.length() || edge.label.charAt(name.length()) == '[')) { if (inputString.length() > 0) { inputString.append(", "); } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Mon Mar 23 10:27:17 2015 -0700 @@ -75,6 +75,7 @@ public static final String NODE_ID_PROPERTY = "id"; public static final String FROM_PROPERTY = "from"; public static final String TO_PROPERTY = "to"; + public static final String TYPE_PROPERTY = "type"; public static final String PROPERTY_NAME_PROPERTY = "name"; public static final String GRAPH_NAME_PROPERTY = "name"; public static final String FROM_INDEX_PROPERTY = "fromIndex"; @@ -387,6 +388,7 @@ int from = -1; int to = -1; String label = null; + String type = null; try { String fromIndexString = readAttribute(FROM_INDEX_PROPERTY); @@ -403,6 +405,7 @@ } label = readAttribute(LABEL_PROPERTY); + type = readAttribute(TYPE_PROPERTY); from = lookupID(readRequiredAttribute(FROM_PROPERTY)); to = lookupID(readRequiredAttribute(TO_PROPERTY)); @@ -410,7 +413,7 @@ throw new SAXException(e); } - InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, ""); + InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, type == null ? "" : type); return start(conn); } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java Mon Mar 23 10:27:17 2015 -0700 @@ -240,6 +240,7 @@ } p.setProperty(Parser.TO_PROPERTY, Integer.toString(edge.getTo())); p.setProperty(Parser.FROM_PROPERTY, Integer.toString(edge.getFrom())); + p.setProperty(Parser.TYPE_PROPERTY, edge.getType()); return p; } } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd Mon Mar 23 10:27:17 2015 -0700 @@ -109,6 +109,7 @@ + diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml --- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml Mon Mar 23 10:27:17 2015 -0700 @@ -4,6 +4,13 @@ *** EDIT ../build.xml INSTEAD *** --> + + + + + + + You must set 'suite.dir' to point to your containing module suite @@ -16,13 +23,21 @@ + + + + + + + - - + + + - + diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties --- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties Mon Mar 23 10:27:17 2015 -0700 @@ -1,5 +1,5 @@ # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=09ba2a87 -nbproject/build-impl.xml.script.CRC32=19fb08e0 -nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1 +nbproject/build-impl.xml.script.CRC32=e4293f0e +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1 diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml --- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml Mon Mar 23 10:27:17 2015 -0700 @@ -4,6 +4,13 @@ *** EDIT ../build.xml INSTEAD *** --> + + + + + + + You must set 'suite.dir' to point to your containing module suite @@ -16,13 +23,21 @@ + + + + + + + - - + + + - + diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties --- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties Mon Mar 23 10:27:17 2015 -0700 @@ -4,5 +4,5 @@ # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=79002a09 -nbproject/build-impl.xml.script.CRC32=7ac2ee25 -nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1 +nbproject/build-impl.xml.script.CRC32=2867f2d5 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1 diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml --- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml Mon Mar 23 10:27:17 2015 -0700 @@ -23,6 +23,14 @@ + com.sun.hotspot.igv.layout + + + + 1.0 + + + com.sun.hotspot.igv.graph diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java Mon Mar 23 10:27:17 2015 -0700 @@ -33,7 +33,6 @@ import java.awt.Color; import java.util.HashMap; import java.util.List; -import java.util.regex.Pattern; /** * Filter that colors usage and successor edges differently. @@ -42,7 +41,7 @@ */ public class GraalEdgeColorFilter extends AbstractFilter { - private HashMap usageColor = new HashMap<>(); + private final HashMap usageColor = new HashMap<>(); private Color otherUsageColor = Color.BLACK; public GraalEdgeColorFilter() { diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter Fri Mar 20 17:26:26 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -var f = new CombineFilter("Combine Filter"); -f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", ".*"), new Properties.RegexpPropertyMatcher("class", "BeginNode"), false, "shortName")); -f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", "EndNode"), new Properties.RegexpPropertyMatcher("class", ".*"), true, "shortName")); -f.apply(graph); diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter Mon Mar 23 10:27:17 2015 -0700 @@ -1,5 +1,5 @@ colorize("name", ".*", white); -colorize("name", "Begin|EndNode|LoopBegin|LoopEnd|LoopExit|Return", orange); +colorize("name", "Begin|KillingBegin|EndNode|LoopBegin|LoopEnd|LoopExit|Return", orange); colorize("name", "Phi.*|ValueProxy", magenta); colorize("name", "FrameState@.*", new java.awt.Color(0.5, 0.8, 1.0)); colorize("name", "If|Merge", pink); diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter Fri Mar 20 17:26:26 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -colorize("class", "FrameState", red); -colorize("locks", "", gray); \ No newline at end of file diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/reduceEdges.filter --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/reduceEdges.filter Mon Mar 23 10:27:17 2015 -0700 @@ -0,0 +1,3 @@ +split("class", "ConstantLocationNode"); +split("class", "ParameterNode"); +split("class", "ConstantNode"); diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml Mon Mar 23 10:27:17 2015 -0700 @@ -18,7 +18,7 @@ - + @@ -26,10 +26,6 @@ - - - - diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java --- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java Mon Mar 23 10:27:17 2015 -0700 @@ -41,8 +41,9 @@ private InputGraph graph; private int curId; private String nodeText; - private Font font; - private Font slotFont; + private final Font font; + private final Font slotFont; + private final Font boldFont; public Font getFont() { return font; @@ -51,12 +52,17 @@ public Font getSlotFont() { return slotFont; } + + public Font getBoldFont() { + return boldFont; + } private Diagram() { figures = new ArrayList<>(); this.nodeText = ""; - this.font = new Font("Arial", Font.PLAIN, 13); + this.font = new Font("Arial", Font.PLAIN, 12); this.slotFont = new Font("Arial", Font.PLAIN, 10); + this.boldFont = this.font.deriveFont(Font.BOLD); } public String getNodeText() { diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java --- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java Mon Mar 23 10:27:17 2015 -0700 @@ -33,14 +33,10 @@ import java.util.List; import java.util.*; -/** - * - * @author Thomas Wuerthinger - */ public class Figure extends Properties.Entity implements Source.Provider, Vertex { - public static final int INSET = 12; - public static int SLOT_WIDTH = 12; + public static final int INSET = 8; + public static int SLOT_WIDTH = 10; public static final int OVERLAPPING = 6; public static final int SLOT_START = 4; public static final int SLOT_OFFSET = 8; diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java --- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java Mon Mar 23 10:27:17 2015 -0700 @@ -43,8 +43,8 @@ public static final int CROSSING_ITERATIONS = 2; public static final int DUMMY_HEIGHT = 1; public static final int DUMMY_WIDTH = 1; - public static final int X_OFFSET = 9; - public static final int LAYER_OFFSET = 30; + public static final int X_OFFSET = 8; + public static final int LAYER_OFFSET = 8; public static final int MAX_LAYER_LENGTH = -1; public static final int MIN_LAYER_DIFFERENCE = 1; public static final int VIP_BONUS = 10; @@ -75,8 +75,6 @@ private LayoutGraph graph; private List[] layers; private int layerCount; - private Set firstLayerHint; - private Set lastLayerHint; private Set importantLinks; private Set linksToFollow; @@ -181,17 +179,15 @@ @Override public void doLayout(LayoutGraph graph) { - doLayout(graph, new HashSet(), new HashSet(), new HashSet()); + doLayout(graph, new HashSet()); } @Override - public void doLayout(LayoutGraph graph, Set firstLayerHint, Set lastLayerHint, Set importantLinks) { + public void doLayout(LayoutGraph graph, Set importantLinks) { this.importantLinks = importantLinks; this.graph = graph; - this.firstLayerHint = firstLayerHint; - this.lastLayerHint = lastLayerHint; vertexToLayoutNode = new HashMap<>(); reversedLinks = new HashSet<>(); @@ -219,7 +215,6 @@ } for (LayoutEdge e : tmpArr) { - //System.out.println("Removed " + e); e.from.succs.remove(e); e.to.preds.remove(e); } @@ -302,8 +297,6 @@ Collections.reverse(points); - - if (cur.vertex == null && cur.preds.size() == 0) { if (reversedLinkEndPoints.containsKey(e.link)) { @@ -364,7 +357,7 @@ LayoutNode cur = e.to; LayoutNode other = e.from; LayoutEdge curEdge = e; - while (cur.vertex == null && cur.succs.size() != 0) { + while (cur.vertex == null && !cur.succs.isEmpty()) { if (points.size() > 1 && points.get(points.size() - 1).x == cur.x + cur.width / 2 && points.get(points.size() - 2).x == cur.x + cur.width / 2) { points.remove(points.size() - 1); } @@ -373,7 +366,7 @@ points.remove(points.size() - 1); } points.add(new Point(cur.x + cur.width / 2, cur.y + cur.height)); - if (cur.succs.size() == 0) { + if (cur.succs.isEmpty()) { break; } assert cur.succs.size() == 1; @@ -381,15 +374,13 @@ cur = curEdge.to; } - p = new Point(cur.x + curEdge.relativeTo, cur.y + cur.yOffset + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y)); points.add(p); if (curEdge.to.inOffsets.containsKey(curEdge.relativeTo)) { points.add(new Point(p.x, p.y + curEdge.to.inOffsets.get(curEdge.relativeTo) + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y))); } - - if (cur.succs.size() == 0 && cur.vertex == null) { + if (cur.succs.isEmpty() && cur.vertex == null) { if (reversedLinkStartPoints.containsKey(e.link)) { for (Point p1 : reversedLinkStartPoints.get(e.link)) { points.add(0, new Point(p1.x + other.x, p1.y + other.y)); @@ -528,13 +519,34 @@ private static final Comparator nodeProcessingDownComparator = new Comparator() { @Override public int compare(LayoutNode n1, LayoutNode n2) { + int n1VIP = 0; + for (LayoutEdge e : n1.preds) { + if (e.vip) { + n1VIP++; + } + } + int n2VIP = 0; + for (LayoutEdge e : n2.preds) { + if (e.vip) { + n2VIP++; + } + } + if (n1VIP != n2VIP) { + return n2VIP - n1VIP; + } if (n1.vertex == null) { if (n2.vertex == null) { return 0; } + if (n1.preds.size() == 1 && n1.preds.get(0).from.vertex != null) { + return 1; + } return -1; } if (n2.vertex == null) { + if (n2.preds.size() == 1 && n2.preds.get(0).from.vertex != null) { + return -1; + } return 1; } return n1.preds.size() - n2.preds.size(); @@ -544,15 +556,36 @@ @Override public int compare(LayoutNode n1, LayoutNode n2) { + int n1VIP = 0; + for (LayoutEdge e : n1.succs) { + if (e.vip) { + n1VIP++; + } + } + int n2VIP = 0; + for (LayoutEdge e : n2.succs) { + if (e.vip) { + n2VIP++; + } + } if (n1.vertex == null) { if (n2.vertex == null) { return 0; } + if (n1.succs.size() == 1 && n1.succs.get(0).to.vertex != null) { + return 1; + } return -1; } if (n2.vertex == null) { + if (n2.succs.size() == 1 && n2.succs.get(0).to.vertex != null) { + return -1; + } return 1; } + if (n1VIP != n2VIP) { + return n2VIP - n1VIP; + } return n1.succs.size() - n2.succs.size(); } }; @@ -568,7 +601,7 @@ n.x = space[n.layer].get(n.pos); } } - + @SuppressWarnings("unchecked") private void createArrays() { space = new ArrayList[layers.length]; @@ -600,13 +633,23 @@ initialPositions(); for (int i = 0; i < SWEEP_ITERATIONS; i++) { sweepDown(); + adjustSpace(); sweepUp(); + adjustSpace(); } - + sweepDown(); - //for (int i = 0; i < SWEEP_ITERATIONS; i++) { - // doubleSweep(); - //} + } + + private void adjustSpace() { + for (int i = 0; i < layers.length; i++) { + // space[i] = new ArrayList<>(); + int curX = 0; + for (LayoutNode n : layers[i]) { + space[i].add(n.x); +// curX += n.width + xOffset; + } + } } private int calculateOptimalDown(LayoutNode n) { @@ -614,22 +657,38 @@ if (size == 0) { return n.x; } - int[] values = new int[size]; - for (int i = 0; i < size; i++) { - LayoutEdge e = n.preds.get(i); - values[i] = e.from.x + e.relativeFrom - e.relativeTo; + int vipCount = 0; + for (LayoutEdge e : n.preds) { if (e.vip) { - return values[i]; + vipCount++; } } - return median(values); + + if (vipCount == 0) { + int[] values = new int[size]; + for (int i = 0; i < size; i++) { + LayoutEdge e = n.preds.get(i); + values[i] = e.from.x + e.relativeFrom - e.relativeTo; + } + return median(values); + } else { + int z = 0; + int[] values = new int[vipCount]; + for (int i = 0; i < size; i++) { + LayoutEdge e = n.preds.get(i); + if (e.vip) { + values[z++] = e.from.x + e.relativeFrom - e.relativeTo; + } + } + return median(values); + } } private int calculateOptimalBoth(LayoutNode n) { if (n.preds.size() == n.succs.size()) { return n.x; } - + int[] values = new int[n.preds.size() + n.succs.size()]; int i = 0; @@ -747,7 +806,7 @@ n.x = pos; } - assert minX <= maxX; + assert minX <= maxX : minX + " vs " + maxX; } treeSet.add(n); @@ -769,7 +828,7 @@ assert n.layer < layerCount; } } - + @SuppressWarnings("unchecked") private void createLayers() { layers = new List[layerCount]; @@ -789,7 +848,7 @@ if (n.layer == 0) { layers[0].add(n); visited.add(n); - } else if (n.preds.size() == 0) { + } else if (n.preds.isEmpty()) { layers[n.layer].add(n); visited.add(n); } @@ -806,7 +865,6 @@ } } - updatePositions(); initX(); @@ -816,11 +874,7 @@ downSweep(); upSweep(); } - if (reversedLinks.isEmpty()) { - // This graph seems to be a tree or forest. - // A final down-sweep will usually give us a better layout. - downSweep(); - } + downSweep(); } private void initX() { @@ -869,8 +923,8 @@ if (e.vip) { factor = VIP_BONUS; } - sum += cur*factor; - count+=factor; + sum += cur * factor; + count += factor; } if (count > 0) { @@ -879,7 +933,6 @@ } } - updateCrossingNumbers(i, true); Collections.sort(layers[i], crossingNodeComparator); updateXOfLayer(i); @@ -940,8 +993,8 @@ if (e.vip) { factor = VIP_BONUS; } - sum += cur*factor; - count+=factor; + sum += cur * factor; + count += factor; } if (count > 0) { @@ -1012,7 +1065,7 @@ } curY += maxHeight + baseLine + bottomBaseLine; - curY += layerOffset + (int) Math.sqrt(maxXOffset); + curY += layerOffset + ((int) (Math.sqrt(maxXOffset) * 1.5)); } } } @@ -1041,7 +1094,6 @@ protected void run() { oldNodeCount = nodes.size(); - if (combine == Combine.SAME_OUTPUTS) { Comparator comparator = new Comparator() { @@ -1154,7 +1206,6 @@ maxLayer = Math.max(maxLayer, curEdge.to.layer); } - int cnt = maxLayer - n.layer - 1; LayoutEdge[] edges = new LayoutEdge[cnt]; LayoutNode[] nodes = new LayoutNode[cnt]; @@ -1279,91 +1330,109 @@ @Override protected void run() { - - List insertOrder = new ArrayList<>(); + assignLayerDownwards(); + assignLayerUpwards(); + } - HashSet set = new HashSet<>(); + private void assignLayerDownwards() { + ArrayList hull = new ArrayList<>(); for (LayoutNode n : nodes) { - if (n.preds.size() == 0) { - set.add(n); - insertOrder.add(n); + if (n.preds.isEmpty()) { + hull.add(n); n.layer = 0; } } int z = minLayerDifference; - HashSet newSet = new HashSet<>(); - HashSet failed = new HashSet<>(); - while (!set.isEmpty()) { - - newSet.clear(); - failed.clear(); - - for (LayoutNode n : set) { - + while (!hull.isEmpty()) { + ArrayList newSet = new ArrayList<>(); + for (LayoutNode n : hull) { for (LayoutEdge se : n.succs) { LayoutNode s = se.to; - if (!newSet.contains(s) && !failed.contains(s)) { - boolean ok = true; + if (s.layer != -1) { + // This node was assigned before. + } else { + boolean unassignedPred = false; for (LayoutEdge pe : s.preds) { LayoutNode p = pe.from; - if (p.layer == -1) { - ok = false; + if (p.layer == -1 || p.layer >= z) { + // This now has an unscheduled successor or a successor that was scheduled only in this round. + unassignedPred = true; break; } } - if (ok) { + if (unassignedPred) { + // This successor node can not yet be assigned. + } else { + s.layer = z; newSet.add(s); - } else { - failed.add(s); } } } - } - for (LayoutNode n : newSet) { - n.layer = z; - insertOrder.add(n); - } - - // Swap sets - HashSet tmp = set; - set = newSet; - newSet = tmp; + hull = newSet; z += minLayerDifference; } - optimize(insertOrder); + layerCount = z - minLayerDifference; + for (LayoutNode n : nodes) { + n.layer = (layerCount - 1 - n.layer); + } + } + + private void assignLayerUpwards() { + ArrayList hull = new ArrayList<>(); + for (LayoutNode n : nodes) { + if (n.succs.isEmpty()) { + hull.add(n); + } else { + n.layer = -1; + } + } + + int z = minLayerDifference; + while (!hull.isEmpty()) { + ArrayList newSet = new ArrayList<>(); + for (LayoutNode n : hull) { + if (n.layer < z) { + for (LayoutEdge se : n.preds) { + LayoutNode s = se.from; + if (s.layer != -1) { + // This node was assigned before. + } else { + boolean unassignedSucc = false; + for (LayoutEdge pe : s.succs) { + LayoutNode p = pe.to; + if (p.layer == -1 || p.layer >= z) { + // This now has an unscheduled successor or a successor that was scheduled only in this round. + unassignedSucc = true; + break; + } + } + + if (unassignedSucc) { + // This predecessor node can not yet be assigned. + } else { + s.layer = z; + newSet.add(s); + } + } + } + } else { + newSet.add(n); + } + } + + hull = newSet; + z += minLayerDifference; + } layerCount = z - minLayerDifference; - for (Vertex v : lastLayerHint) { - - LayoutNode n = vertexToLayoutNode.get(v); - assert n.succs.size() == 0; - n.layer = layerCount - 1; - } - - for (Vertex v : firstLayerHint) { - LayoutNode n = vertexToLayoutNode.get(v); - assert n.preds.size() == 0; - n.layer = 0; - assert n.layer == 0; - } - } - - public void optimize(List insertOrder) { - for (int i = insertOrder.size() - 1; i >= 0; i--) { - LayoutNode cur = insertOrder.get(i); - if (cur.succs.size() > cur.preds.size()) { - int minLayer = cur.succs.get(0).to.layer; - for (LayoutEdge e : cur.succs) { - minLayer = Math.min(minLayer, e.to.layer); - } - cur.layer = minLayer - 1; - } + for (LayoutNode n : nodes) { + n.layer = (layerCount - 1 - n.layer); } } @@ -1415,7 +1484,6 @@ } } - // Start DFS and reverse back edges visited = new HashSet<>(); active = new HashSet<>(); @@ -1423,7 +1491,6 @@ DFS(node); } - for (LayoutNode node : nodes) { SortedSet reversedDown = new TreeSet<>(); @@ -1434,7 +1501,6 @@ } } - SortedSet reversedUp = null; if (reversedDown.size() == 0) { reversedUp = new TreeSet<>(Collections.reverseOrder()); @@ -1522,7 +1588,6 @@ curX += offset; node.bottomYOffset += offset; - endPoints.add(new Point(pos, node.height)); endPoints.add(new Point(pos, oldNodeHeight)); for (LayoutEdge e : reversedPreds) { @@ -1530,7 +1595,6 @@ } } - if (minX < 0) { for (LayoutEdge e : node.preds) { e.relativeTo -= minX; @@ -1650,6 +1714,13 @@ @Override public int compare(Link l1, Link l2) { + if (l1.isVIP() && !l2.isVIP()) { + return -1; + } + + if (!l1.isVIP() && l2.isVIP()) { + return 1; + } int result = l1.getFrom().getVertex().compareTo(l2.getFrom().getVertex()); if (result != 0) { @@ -1698,15 +1769,15 @@ edge.relativeFrom = l.getFrom().getRelativePosition().x; edge.relativeTo = l.getTo().getRelativePosition().x; edge.link = l; + edge.vip = l.isVIP(); edge.from.succs.add(edge); edge.to.preds.add(edge); - edge.vip = l.isVIP(); - //assert edge.from != edge.to; // No self-loops allowed + //assert edge.from != edge.to; // No self-loops allowed } for (Link l : importantLinks) { - if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex()) || - vertexToLayoutNode.containsKey(l.getTo().getVertex())) { + if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex()) + || vertexToLayoutNode.containsKey(l.getTo().getVertex())) { continue; } LayoutNode from = vertexToLayoutNode.get(l.getFrom().getVertex()); diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java --- a/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java Mon Mar 23 10:27:17 2015 -0700 @@ -33,7 +33,7 @@ public void doLayout(LayoutGraph graph); - public void doLayout(LayoutGraph graph, Set firstLayerHint, Set lastLayerHint, Set importantLinks); + public void doLayout(LayoutGraph graph, Set importantLinks); public void doRouting(LayoutGraph graph); } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml --- a/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml Mon Mar 23 10:27:17 2015 -0700 @@ -4,6 +4,13 @@ *** EDIT ../build.xml INSTEAD *** --> + + + + + + + You must set 'suite.dir' to point to your containing module suite @@ -16,13 +23,21 @@ + + + + + + + - - + + + - + diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties --- a/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties Mon Mar 23 10:27:17 2015 -0700 @@ -1,5 +1,5 @@ # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=13553862 -nbproject/build-impl.xml.script.CRC32=5dca457e -nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1 +nbproject/build-impl.xml.script.CRC32=3db87c68 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1 diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java --- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java Mon Mar 23 10:27:17 2015 -0700 @@ -34,7 +34,7 @@ */ public class ColorIcon implements Icon { - private Color color; + private final Color color; public ColorIcon(Color c) { color = c; @@ -42,8 +42,10 @@ @Override public void paintIcon(Component c, Graphics g, int x, int y) { + Color oldColor = g.getColor(); g.setColor(color); g.fillRect(x, y, 16, 16); + g.setColor(oldColor); } @Override diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Mon Mar 23 10:27:17 2015 -0700 @@ -71,6 +71,7 @@ private Lookup lookup; private InstanceContent content; private Action[] actions; + private Action[] actionsWithSelection; private LayerWidget connectionLayer; private JScrollPane scrollPane; private UndoRedo.Manager undoRedoManager; @@ -100,7 +101,7 @@ public static final float ZOOM_MAX_FACTOR = 3.0f; public static final float ZOOM_MIN_FACTOR = 0.0f;//0.15f; public static final float ZOOM_INCREMENT = 1.5f; - public static final int SLOT_OFFSET = 6; + public static final int SLOT_OFFSET = 8; public static final int ANIMATION_LIMIT = 40; private PopupMenuProvider popupMenuProvider = new PopupMenuProvider() { @@ -374,9 +375,10 @@ } }; - public DiagramScene(Action[] actions, DiagramViewModel model) { + public DiagramScene(Action[] actions, Action[] actionsWithSelection, DiagramViewModel model) { this.actions = actions; + this.actionsWithSelection = actionsWithSelection; content = new InstanceContent(); lookup = new AbstractLookup(content); @@ -399,6 +401,9 @@ blockLayer = new LayerWidget(this); this.addChild(blockLayer); + connectionLayer = new LayerWidget(this); + this.addChild(connectionLayer); + mainLayer = new LayerWidget(this); this.addChild(mainLayer); @@ -410,9 +415,6 @@ bottomRight.setPreferredLocation(new Point(-BORDER_SIZE, -BORDER_SIZE)); this.addChild(bottomRight); - connectionLayer = new LayerWidget(this); - this.addChild(connectionLayer); - LayerWidget selectionLayer = new LayerWidget(this); this.addChild(selectionLayer); @@ -451,12 +453,21 @@ } public boolean isAllVisible() { - return getModel().getHiddenNodes().size() == 0; + return getModel().getHiddenNodes().isEmpty(); } public Action createGotoAction(final Figure f) { final DiagramScene diagramScene = this; - Action a = new AbstractAction() { + String name = f.getLines()[0]; + + name += " ("; + + final boolean hidden = !this.getWidget(f, FigureWidget.class).isVisible(); + if (hidden) { + name += "hidden"; + } + name += ")"; + Action a = new AbstractAction(name, new ColorIcon(f.getColor())) { @Override public void actionPerformed(ActionEvent e) { @@ -465,16 +476,6 @@ }; a.setEnabled(true); - a.putValue(Action.SMALL_ICON, new ColorIcon(f.getColor())); - String name = f.getLines()[0]; - - name += " ("; - - if (!this.getWidget(f, FigureWidget.class).isVisible()) { - name += "hidden"; - } - name += ")"; - a.putValue(Action.NAME, name); return a; } @@ -538,8 +539,6 @@ } private void smallUpdate(boolean relayout) { - - System.out.println("smallUpdate " + relayout); this.updateHiddenNodes(model.getHiddenNodes(), relayout); boolean b = this.getUndoRedoEnabled(); this.setUndoRedoEnabled(false); @@ -559,8 +558,6 @@ } private void relayout(Set oldVisibleWidgets) { - System.out.println("relayout called with old visible widgets: " + oldVisibleWidgets); - Diagram diagram = getModel().getDiagramToView(); HashSet
figures = new HashSet<>(); @@ -589,8 +586,6 @@ private void relayoutWithoutLayout(Set oldVisibleWidgets) { - System.out.println("relayout without layout with visible widgets: " + oldVisibleWidgets); - Diagram diagram = getModel().getDiagramToView(); int maxX = -BORDER_SIZE; @@ -958,8 +953,6 @@ private void updateHiddenNodes(Set newHiddenNodes, boolean doRelayout) { - System.out.println("newHiddenNodes: " + newHiddenNodes); - Diagram diagram = getModel().getDiagramToView(); assert diagram != null; @@ -1027,7 +1020,7 @@ private void showFigure(Figure f) { HashSet newHiddenNodes = new HashSet<>(getModel().getHiddenNodes()); newHiddenNodes.removeAll(f.getSource().getSourceNodesAsSet()); - updateHiddenNodes(newHiddenNodes, true); + this.model.setHiddenNodes(newHiddenNodes); } public void show(final Figure f) { @@ -1062,7 +1055,12 @@ public JPopupMenu createPopupMenu() { JPopupMenu menu = new JPopupMenu(); - for (Action a : actions) { + + Action[] currentActions = actionsWithSelection; + if (this.getSelectedObjects().isEmpty()) { + currentActions = actions; + } + for (Action a : currentActions) { if (a == null) { menu.addSeparator(); } else { diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Mon Mar 23 10:27:17 2015 -0700 @@ -246,7 +246,7 @@ if (last == null) { curColor = Color.green; } else { - if (last.equals(cur)) { + if (last.equals(cur) && last.getProperties().equals(cur.getProperties())) { if (curColor == Color.black) { curColor = Color.white; } @@ -268,7 +268,6 @@ } public void showNot(final Set nodes) { - System.out.println("Shownot called with " + nodes); setHiddenNodes(nodes); } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java Mon Mar 23 10:27:17 2015 -0700 @@ -178,12 +178,17 @@ null, ZoomInAction.get(ZoomInAction.class), ZoomOutAction.get(ZoomOutAction.class), + }; + + + Action[] actionsWithSelection = new Action[]{ + ExtractAction.get(ExtractAction.class), + ShowAllAction.get(HideAction.class), null, ExpandPredecessorsAction.get(ExpandPredecessorsAction.class), ExpandSuccessorsAction.get(ExpandSuccessorsAction.class) }; - initComponents(); ToolbarPool.getDefault().setPreferredIconSize(16); @@ -201,7 +206,7 @@ JScrollPane pane = new JScrollPane(rangeSlider, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); container.add(BorderLayout.CENTER, pane); - scene = new DiagramScene(actions, rangeSliderModel); + scene = new DiagramScene(actions, actionsWithSelection, rangeSliderModel); content = new InstanceContent(); graphContent = new InstanceContent(); this.associateLookup(new ProxyLookup(new Lookup[]{scene.getLookup(), new AbstractLookup(graphContent), new AbstractLookup(content)})); diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java Mon Mar 23 10:27:17 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,11 +62,7 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMenuProvider, DoubleClickHandler { public static final boolean VERTICAL_LAYOUT = true; - //public static final int MAX_STRING_LENGTH = 20; private static final double LABEL_ZOOM_FACTOR = 0.3; - private static final double ZOOM_FACTOR = 0.1; - private Font font; - private Font boldFont; private Figure figure; private Widget leftWidget; private Widget rightWidget; @@ -74,7 +70,7 @@ private ArrayList labelWidgets; private DiagramScene diagramScene; private boolean boundary; - private Node node; + private final Node node; private Widget dummyTop; public void setBoundary(boolean b) { @@ -89,11 +85,10 @@ return node; } - @Override - public boolean isHitAt(Point localLocation) { - return middleWidget.isHitAt(localLocation); - } - + @Override + public boolean isHitAt(Point localLocation) { + return middleWidget.isHitAt(localLocation); + } public FigureWidget(final Figure f, WidgetAction hoverAction, WidgetAction selectAction, DiagramScene scene, Widget parent) { @@ -103,23 +98,20 @@ assert this.getScene().getView() != null; this.figure = f; - font = f.getDiagram().getFont(); - boldFont = f.getDiagram().getFont().deriveFont(Font.BOLD); this.setCheckClipping(true); this.diagramScene = scene; parent.addChild(this); - Widget outer = new Widget(scene); - outer.setBackground(f.getColor()); - outer.setLayout(LayoutFactory.createOverlayLayout()); - + Widget outer = new Widget(scene); + outer.setBackground(f.getColor()); + outer.setLayout(LayoutFactory.createOverlayLayout()); + middleWidget = new Widget(scene); middleWidget.setLayout(LayoutFactory.createVerticalFlowLayout(LayoutFactory.SerialAlignment.CENTER, 0)); middleWidget.setBackground(f.getColor()); middleWidget.setOpaque(true); - //middleWidget.setBorder(BorderFactory.createLineBorder(Color.BLACK)); middleWidget.getActions().addAction(new DoubleClickAction(this)); - middleWidget.setCheckClipping(true); + middleWidget.setCheckClipping(true); labelWidgets = new ArrayList<>(); @@ -129,7 +121,6 @@ dummyTop.setMinimumSize(new Dimension(Figure.INSET / 2, 1)); middleWidget.addChild(dummyTop); - for (String cur : strings) { String displayString = cur; @@ -138,11 +129,11 @@ labelWidgets.add(lw); middleWidget.addChild(lw); lw.setLabel(displayString); - lw.setFont(font); + lw.setFont(figure.getDiagram().getFont()); lw.setForeground(Color.BLACK); lw.setAlignment(LabelWidget.Alignment.CENTER); lw.setVerticalAlignment(LabelWidget.VerticalAlignment.CENTER); - lw.setBorder(BorderFactory.createEmptyBorder()); + lw.setBorder(BorderFactory.createEmptyBorder()); } Widget dummyBottom = new Widget(scene); @@ -150,7 +141,6 @@ middleWidget.addChild(dummyBottom); middleWidget.setPreferredBounds(new Rectangle(0, Figure.SLOT_WIDTH - Figure.OVERLAPPING, f.getWidth(), f.getHeight())); - //outer.addChild(middleWidget); this.addChild(middleWidget); // Initialize node for property sheet @@ -178,49 +168,22 @@ protected void notifyStateChanged(ObjectState previousState, ObjectState state) { super.notifyStateChanged(previousState, state); - Color borderColor = Color.BLACK; - Color innerBorderColor = getFigure().getColor(); - int thickness = 1; - boolean repaint = false; - Font f = font; - if (state.isSelected() || state.isHighlighted()) { - thickness = 2; - } - if(state.isSelected()) { - f = boldFont; - innerBorderColor = borderColor; - } else { - } - - if (state.isHighlighted()) { - innerBorderColor = borderColor = Color.BLUE; - repaint = true; - } else { - repaint = true; - } - - if (state.isHovered() != previousState.isHovered()) { - - /* - if (state.isHovered()) { - diagramScene.addAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet()); - } else { - diagramScene.removeAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet()); - }*/ - repaint = true; + Font font = this.figure.getDiagram().getFont(); + if (state.isSelected()) { + font = this.figure.getDiagram().getBoldFont(); } - if (state.isSelected() != previousState.isSelected()) { - repaint = true; + Color borderColor = Color.BLACK; + Color innerBorderColor = getFigure().getColor(); + if (state.isHighlighted()) { + innerBorderColor = borderColor = Color.BLUE; } - if (repaint) { - middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1))); - for (LabelWidget labelWidget : labelWidgets) { - labelWidget.setFont(f); - } - repaint(); + middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1))); + for (LabelWidget labelWidget : labelWidgets) { + labelWidget.setFont(font); } + repaint(); } public String getName() { @@ -246,7 +209,6 @@ } if (diagramScene.getZoomFactor() < LABEL_ZOOM_FACTOR) { - for (LabelWidget labelWidget : labelWidgets) { labelWidget.setVisible(false); } @@ -263,19 +225,15 @@ getScene().getGraphics().setComposite(oldComposite); } } - + @Override public JPopupMenu getPopupMenu(Widget widget, Point point) { JPopupMenu menu = diagramScene.createPopupMenu(); menu.addSeparator(); - - JMenu predecessors = new JMenu("Nodes Above"); - predecessors.addMenuListener(new NeighborMenuListener(predecessors, getFigure(), false)); - menu.add(predecessors); - - JMenu successors = new JMenu("Nodes Below"); - successors.addMenuListener(new NeighborMenuListener(successors, getFigure(), true)); - menu.add(successors); + + build(menu, getFigure(), this, false, diagramScene); + menu.addSeparator(); + build(menu, getFigure(), this, true, diagramScene); if (getFigure().getSubgraphs() != null) { menu.addSeparator(); @@ -283,7 +241,7 @@ menu.add(subgraphs); final GraphViewer viewer = Lookup.getDefault().lookup(GraphViewer.class); - for(final InputGraph subgraph : getFigure().getSubgraphs()) { + for (final InputGraph subgraph : getFigure().getSubgraphs()) { Action a = new AbstractAction() { @Override @@ -301,10 +259,45 @@ return menu; } + public static void build(JPopupMenu menu, Figure figure, FigureWidget figureWidget, boolean successors, DiagramScene diagramScene) { + Set
set = figure.getPredecessorSet(); + if (successors) { + set = figure.getSuccessorSet(); + } + + boolean first = true; + for (Figure f : set) { + if (f == figure) { + continue; + } + + if (first) { + first = false; + } else { + menu.addSeparator(); + } + + Action go = diagramScene.createGotoAction(f); + menu.add(go); + + JMenu preds = new JMenu("Nodes Above"); + preds.addMenuListener(figureWidget.new NeighborMenuListener(preds, f, false)); + menu.add(preds); + + JMenu succs = new JMenu("Nodes Below"); + succs.addMenuListener(figureWidget.new NeighborMenuListener(succs, f, true)); + menu.add(succs); + } + + if (figure.getPredecessorSet().isEmpty() && figure.getSuccessorSet().isEmpty()) { + menu.add("(none)"); + } + } + /** * Builds the submenu for a figure's neighbors on demand. */ - private class NeighborMenuListener implements MenuListener { + public class NeighborMenuListener implements MenuListener { private final JMenu menu; private final Figure figure; @@ -323,38 +316,7 @@ return; } - Set
set = figure.getPredecessorSet(); - if (successors) { - set = figure.getSuccessorSet(); - } - - boolean first = true; - for (Figure f : set) { - if (f == figure) { - continue; - } - - if (first) { - first = false; - } else { - menu.addSeparator(); - } - - Action go = diagramScene.createGotoAction(f); - menu.add(go); - - JMenu preds = new JMenu("Nodes Above"); - preds.addMenuListener(new NeighborMenuListener(preds, f, false)); - menu.add(preds); - - JMenu succs = new JMenu("Nodes Below"); - succs.addMenuListener(new NeighborMenuListener(succs, f, true)); - menu.add(succs); - } - - if (menu.getItemCount() == 0) { - menu.add("(none)"); - } + build(menu.getPopupMenu(), figure, FigureWidget.this, successors, diagramScene); } @Override diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java Mon Mar 23 10:27:17 2015 -0700 @@ -109,7 +109,6 @@ if (connections.size() > 0) { color = connections.get(0).getColor(); } - this.setToolTipText("" + generateToolTipText(this.connections) + ""); this.setCheckClipping(true); @@ -203,7 +202,7 @@ g.drawLine(from.x, from.y, to.x, to.y); boolean sameFrom = false; - boolean sameTo = successors.size() == 0; + boolean sameTo = successors.isEmpty(); for (LineWidget w : successors) { if (w.getFrom().equals(getTo())) { sameTo = true; diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java Mon Mar 23 10:27:17 2015 -0700 @@ -41,12 +41,9 @@ public OutputSlotWidget(OutputSlot slot, DiagramScene scene, Widget parent, FigureWidget fw) { super(slot, scene, parent, fw); outputSlot = slot; - //init(); - //getFigureWidget().getRightWidget().addChild(this); Point p = outputSlot.getRelativePosition(); p.y += getSlot().getFigure().getHeight() - Figure.SLOT_START; p.x -= this.calculateClientArea().width / 2; - //p.x += this.calculateClientArea().width / 2; this.setPreferredLocation(p); } @@ -56,21 +53,9 @@ @Override protected int calculateSlotWidth() { - List slots = getSlot().getFigure().getOutputSlots(); assert slots.contains(getSlot()); return calculateWidth(slots.size()); } - /* - protected Point calculateRelativeLocation() { - if (getFigureWidget().getBounds() == null) { - return new Point(0, 0); - } - - double x = this.getFigureWidget().getBounds().width; - List slots = outputSlot.getFigure().getOutputSlots(); - assert slots.contains(outputSlot); - return new Point((int) x, (int) (calculateRelativeY(slots.size(), slots.indexOf(outputSlot)))); - }*/ } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java Mon Mar 23 10:27:17 2015 -0700 @@ -59,17 +59,16 @@ this.setToolTipText("" + slot.getToolTipText() + ""); this.setCheckClipping(true); parent.addChild(this); - + //this.setPreferredBounds(this.calculateClientArea()); } - - + @Override protected void notifyStateChanged(ObjectState previousState, ObjectState state) { super.notifyStateChanged(previousState, state); - repaint(); + repaint(); } - + public Slot getSlot() { return slot; } @@ -86,58 +85,59 @@ } Graphics2D g = this.getGraphics(); - // g.setColor(Color.DARK_GRAY); + // g.setColor(Color.DARK_GRAY); int w = this.getBounds().width; int h = this.getBounds().height; - if(getSlot().getSource().getSourceNodes().size() > 0) { + if (getSlot().getSource().getSourceNodes().size() > 0) { final int SMALLER = 0; g.setColor(getSlot().getColor()); int FONT_OFFSET = 2; - + int s = h - SMALLER; int rectW = s; - + Font font = this.getSlot().getFigure().getDiagram().getSlotFont(); - if(this.getState().isSelected()) { + if (this.getState().isSelected()) { font = font.deriveFont(Font.BOLD); } - + if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0) { g.setFont(font); Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g); - rectW = (int)r1.getWidth() + FONT_OFFSET * 2; + rectW = (int) r1.getWidth() + FONT_OFFSET * 2; } - g.fillRect(w/2 - rectW/2, 0, rectW-1, s-1); - - if(this.getState().isHighlighted()) { + g.fillRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1); + + if (this.getState().isHighlighted()) { g.setColor(Color.BLUE); } else { g.setColor(Color.BLACK); } - g.drawRect(w/2 - rectW/2, 0, rectW-1, s-1); - - + g.drawRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1); + if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0 && getScene().getZoomFactor() >= TEXT_ZOOM_FACTOR) { Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g); - g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent()-1);//(int) (r1.getHeight())); + g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent() - 1);//(int) (r1.getHeight())); } - + } else { - if(this.getState().isHighlighted()) { - g.setColor(Color.BLUE); + if (this.getSlot().getConnections().isEmpty()) { + if (this.getState().isHighlighted()) { + g.setColor(Color.BLUE); + } else { + g.setColor(Color.BLACK); + } + int r = 2; + if (slot instanceof OutputSlot) { + g.fillOval(w / 2 - r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2 * r, 2 * r); + } else { + g.fillOval(w / 2 - r, Figure.SLOT_START - r, 2 * r, 2 * r); + } } else { - g.setColor(Color.BLACK); - } - int r = 2; - if (slot instanceof OutputSlot) { - g.fillOval(w/2-r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2*r, 2*r); - //g.fillArc(w / 2 - r, -r, 2*r, 2*r, 180, 180); - } else { - g.fillOval(w/2-r, Figure.SLOT_START - r, 2*r, 2*r); - //g.fillArc(w / 2 - r, h - r, 2*r, 2*r, 0, 180); + // Do not paint a slot with connections. } } } @@ -146,9 +146,9 @@ protected Rectangle calculateClientArea() { return new Rectangle(0, 0, slot.getWidth(), Figure.SLOT_WIDTH); } - + protected abstract int calculateSlotWidth(); - + protected int calculateWidth(int count) { return getFigureWidget().getFigure().getWidth() / count; } @@ -158,19 +158,19 @@ Set hiddenNodes = new HashSet<>(diagramScene.getModel().getHiddenNodes()); if (diagramScene.isAllVisible()) { hiddenNodes = new HashSet<>(diagramScene.getModel().getGraphToView().getGroup().getAllNodes()); - } + } boolean progress = false; - for(Figure f : diagramScene.getModel().getDiagramToView().getFigures()) { - for(Slot s : f.getSlots()) { - if(DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) { + for (Figure f : diagramScene.getModel().getDiagramToView().getFigures()) { + for (Slot s : f.getSlots()) { + if (DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) { progress = true; hiddenNodes.removeAll(f.getSource().getSourceNodesAsSet()); } } } - if(progress) { + if (progress) { this.diagramScene.getModel().showNot(hiddenNodes); } } diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/nbproject/platform.properties --- a/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Mon Mar 23 10:27:17 2015 -0700 @@ -1,114 +1,8 @@ +branding.token=idealgraphvisualizer cluster.path=\ ${nbplatform.active.dir}/ide:\ ${nbplatform.active.dir}/platform -disabled.modules=\ - org.apache.commons.codec,\ - org.apache.commons.httpclient,\ - org.apache.commons.io,\ - org.apache.commons.lang,\ - org.apache.ws.commons.util,\ - org.apache.xmlrpc,\ - org.eclipse.core.contenttype,\ - org.eclipse.core.jobs,\ - org.eclipse.core.net,\ - org.eclipse.core.runtime,\ - org.eclipse.core.runtime.compatibility.auth,\ - org.eclipse.equinox.app,\ - org.eclipse.equinox.common,\ - org.eclipse.equinox.preferences,\ - org.eclipse.equinox.registry,\ - org.eclipse.equinox.security,\ - org.eclipse.jgit,\ - org.eclipse.mylyn.bugzilla.core,\ - org.eclipse.mylyn.commons.core,\ - org.eclipse.mylyn.commons.net,\ - org.eclipse.mylyn.commons.repositories.core,\ - org.eclipse.mylyn.commons.xmlrpc,\ - org.eclipse.mylyn.tasks.core,\ - org.eclipse.mylyn.wikitext.confluence.core,\ - org.eclipse.mylyn.wikitext.core,\ - org.eclipse.mylyn.wikitext.textile.core,\ - org.netbeans.api.debugger,\ - org.netbeans.core.browser,\ - org.netbeans.core.browser.webview,\ - org.netbeans.libs.commons_net,\ - org.netbeans.libs.git,\ - org.netbeans.libs.ini4j,\ - org.netbeans.libs.jsch.agentproxy,\ - org.netbeans.libs.json_simple,\ - org.netbeans.libs.smack,\ - org.netbeans.libs.svnClientAdapter,\ - org.netbeans.libs.svnClientAdapter.javahl,\ - org.netbeans.libs.svnClientAdapter.svnkit,\ - org.netbeans.libs.swingx,\ - org.netbeans.modules.bugtracking,\ - org.netbeans.modules.bugtracking.bridge,\ - org.netbeans.modules.bugzilla,\ - org.netbeans.modules.code.analysis,\ - org.netbeans.modules.css.prep,\ - org.netbeans.modules.db,\ - org.netbeans.modules.db.core,\ - org.netbeans.modules.db.dataview,\ - org.netbeans.modules.db.drivers,\ - org.netbeans.modules.db.kit,\ - org.netbeans.modules.db.metadata.model,\ - org.netbeans.modules.db.mysql,\ - org.netbeans.modules.db.sql.editor,\ - org.netbeans.modules.db.sql.visualeditor,\ - org.netbeans.modules.dbapi,\ - org.netbeans.modules.derby,\ - org.netbeans.modules.editor.global.format,\ - org.netbeans.modules.editor.indent.project,\ - org.netbeans.modules.extexecution.impl,\ - org.netbeans.modules.git,\ - org.netbeans.modules.gototest,\ - org.netbeans.modules.gsf.codecoverage,\ - org.netbeans.modules.gsf.testrunner,\ - org.netbeans.modules.html.angular,\ - org.netbeans.modules.html.knockout,\ - org.netbeans.modules.hudson,\ - org.netbeans.modules.hudson.git,\ - org.netbeans.modules.hudson.mercurial,\ - org.netbeans.modules.hudson.subversion,\ - org.netbeans.modules.hudson.tasklist,\ - org.netbeans.modules.hudson.ui,\ - org.netbeans.modules.jellytools.ide,\ - org.netbeans.modules.languages,\ - org.netbeans.modules.lexer.nbbridge,\ - org.netbeans.modules.localhistory,\ - org.netbeans.modules.mercurial,\ - org.netbeans.modules.mylyn.util,\ - org.netbeans.modules.notifications,\ - org.netbeans.modules.parsing.ui,\ - org.netbeans.modules.project.ant,\ - org.netbeans.modules.projectui.buildmenu,\ - org.netbeans.modules.properties.syntax,\ - org.netbeans.modules.schema2beans,\ - org.netbeans.modules.server,\ - org.netbeans.modules.spellchecker,\ - org.netbeans.modules.spellchecker.apimodule,\ - org.netbeans.modules.spellchecker.bindings.htmlxml,\ - org.netbeans.modules.spellchecker.bindings.properties,\ - org.netbeans.modules.spellchecker.dictionary_en,\ - org.netbeans.modules.spellchecker.kit,\ - org.netbeans.modules.subversion,\ - org.netbeans.modules.swing.validation,\ - org.netbeans.modules.target.iterator,\ - org.netbeans.modules.team.commons,\ - org.netbeans.modules.team.ide,\ - org.netbeans.modules.utilities.project,\ - org.netbeans.modules.versioning,\ - org.netbeans.modules.versioning.core,\ - org.netbeans.modules.versioning.indexingbridge,\ - org.netbeans.modules.versioning.masterfs,\ - org.netbeans.modules.versioning.system.cvss.installer,\ - org.netbeans.modules.versioning.ui,\ - org.netbeans.modules.versioning.util,\ - org.netbeans.modules.web.webkit.debugging,\ - org.netbeans.modules.xml.multiview,\ - org.netbeans.spi.debugger.ui,\ - org.netbeans.spi.viewmodel,\ - org.openidex.util +disabled.modules= nbplatform.active.dir=${suite.dir}/nbplatform nbplatform.default.netbeans.dest.dir=${suite.dir}/nbplatform nbplatform.default.harness.dir=${nbplatform.default.netbeans.dest.dir}/harness diff -r 426e45c75771 -r 3819bcdde898 src/share/tools/IdealGraphVisualizer/nbproject/project.properties --- a/src/share/tools/IdealGraphVisualizer/nbproject/project.properties Fri Mar 20 17:26:26 2015 -0700 +++ b/src/share/tools/IdealGraphVisualizer/nbproject/project.properties Mon Mar 23 10:27:17 2015 -0700 @@ -1,44 +1,50 @@ -app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif -app.name=idealgraphvisualizer -app.title=IdealGraphVisualizer -branding.token=${app.name} -modules=\ - ${project.com.sun.hotspot.igv.graph}:\ - ${project.com.sun.hotspot.igv.coordinator}:\ - ${project.com.sun.hotspot.igv.filter}:\ - ${project.com.sun.hotspot.igv.hierarchicallayout}:\ - ${project.com.sun.hotspot.igv.layout}:\ - ${project.com.sun.hotspot.igv.data}:\ - ${project.com.sun.hotspot.igv.view}:\ - ${project.com.sun.hotspot.igv.bytecodes}:\ - ${project.com.sun.hotspot.igv.difference}:\ - ${project.com.sun.hotspot.igv.settings}:\ - ${project.com.sun.hotspot.igv.util}:\ - ${project.com.sun.hotspot.igv.svg}:\ - ${project.com.sun.hotspot.connection}:\ - ${project.com.sun.hotspot.igv.servercompilerscheduler}:\ - ${project.com.sun.hotspot.igv.filterwindow}:\ - ${project.com.sun.hotspot.igv.selectioncoordinator}:\ - ${project.com.sun.hotspot.igv.graal} -project.com.sun.hotspot.connection=NetworkConnection -project.com.sun.hotspot.igv.bytecodes=Bytecodes -project.com.sun.hotspot.igv.coordinator=Coordinator -project.com.sun.hotspot.igv.data=Data -project.com.sun.hotspot.igv.difference=Difference -project.com.sun.hotspot.igv.filter=Filter -project.com.sun.hotspot.igv.filterwindow=FilterWindow -project.com.sun.hotspot.igv.graal=Graal -project.com.sun.hotspot.igv.graph=Graph -project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout -project.com.sun.hotspot.igv.layout=Layout -project.com.sun.hotspot.igv.selectioncoordinator=SelectionCoordinator -project.com.sun.hotspot.igv.servercompilerscheduler=ServerCompiler -project.com.sun.hotspot.igv.settings=Settings -project.com.sun.hotspot.igv.svg=BatikSVGProxy -project.com.sun.hotspot.igv.view=View -project.com.sun.hotspot.igv.util=Util - -# Disable assertions for RequestProcessor to prevent annoying messages in case -# of multiple SceneAnimator update tasks in the default RequestProcessor. -run.args.extra = -J-server -J-da:org.openide.util.RequestProcessor -J-Xms2g -J-Xmx8g -J-Djava.lang.Integer.IntegerCache.high=20000 -debug.args.extra = -J-server -J-da:org.openide.util.RequestProcessor +app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif +app.name=${branding.token} +app.title=IdealGraphVisualizer +auxiliary.org-netbeans-modules-apisupport-installer.license-type=no +auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false +auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=true +auxiliary.org-netbeans-modules-apisupport-installer.os-solaris=false +auxiliary.org-netbeans-modules-apisupport-installer.os-windows=false +auxiliary.org-netbeans-modules-apisupport-installer.pack200-enabled=false +auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml +modules=\ + ${project.com.sun.hotspot.igv.graph}:\ + ${project.com.sun.hotspot.igv.coordinator}:\ + ${project.com.sun.hotspot.igv.filter}:\ + ${project.com.sun.hotspot.igv.hierarchicallayout}:\ + ${project.com.sun.hotspot.igv.layout}:\ + ${project.com.sun.hotspot.igv.data}:\ + ${project.com.sun.hotspot.igv.view}:\ + ${project.com.sun.hotspot.igv.bytecodes}:\ + ${project.com.sun.hotspot.igv.difference}:\ + ${project.com.sun.hotspot.igv.settings}:\ + ${project.com.sun.hotspot.igv.util}:\ + ${project.com.sun.hotspot.igv.svg}:\ + ${project.com.sun.hotspot.connection}:\ + ${project.com.sun.hotspot.igv.servercompilerscheduler}:\ + ${project.com.sun.hotspot.igv.filterwindow}:\ + ${project.com.sun.hotspot.igv.selectioncoordinator}:\ + ${project.com.sun.hotspot.igv.graal} +project.com.sun.hotspot.connection=NetworkConnection +project.com.sun.hotspot.igv.bytecodes=Bytecodes +project.com.sun.hotspot.igv.coordinator=Coordinator +project.com.sun.hotspot.igv.data=Data +project.com.sun.hotspot.igv.difference=Difference +project.com.sun.hotspot.igv.filter=Filter +project.com.sun.hotspot.igv.filterwindow=FilterWindow +project.com.sun.hotspot.igv.graal=Graal +project.com.sun.hotspot.igv.graph=Graph +project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout +project.com.sun.hotspot.igv.layout=Layout +project.com.sun.hotspot.igv.selectioncoordinator=SelectionCoordinator +project.com.sun.hotspot.igv.servercompilerscheduler=ServerCompiler +project.com.sun.hotspot.igv.settings=Settings +project.com.sun.hotspot.igv.svg=BatikSVGProxy +project.com.sun.hotspot.igv.view=View +project.com.sun.hotspot.igv.util=Util + +# Disable assertions for RequestProcessor to prevent annoying messages in case +# of multiple SceneAnimator update tasks in the default RequestProcessor. +run.args.extra = -J-server -J-da:org.openide.util.RequestProcessor -J-Xms2g -J-Xmx8g -J-Djava.lang.Integer.IntegerCache.high=20000 +debug.args.extra = -J-server -J-da:org.openide.util.RequestProcessor