# HG changeset patch # User Thomas Wuerthinger # Date 1358343675 -3600 # Node ID 69318374c8d789c1a4f7a3eb8689b70367ce64b4 # Parent 729a79037bd5fc73233850ec61767995ad294aaf# Parent 5f00bf5a530d6541bb8dba1fc483376688cb48e8 Merge. diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java --- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Wed Jan 16 14:41:15 2013 +0100 @@ -25,9 +25,6 @@ import java.util.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; /** @@ -55,7 +52,7 @@ } }}; - public ComputeBlockOrder(int maxBlockId, int loopCount, Block startBlock, boolean reorderLoops) { + public ComputeBlockOrder(int maxBlockId, @SuppressWarnings("unused") int loopCount, Block startBlock, @SuppressWarnings("unused") boolean reorderLoops) { List newLinearScanOrder = new ArrayList<>(); List order = new ArrayList<>(); diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Wed Jan 16 14:41:15 2013 +0100 @@ -93,6 +93,8 @@ assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet")); // assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet")); + assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet")); + assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet")); assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet")); } @@ -120,6 +122,14 @@ public static int invokeOverriddenInterfaceMethodSnippet(MultipleImplementorsInterface testInterface) { return testInterface.publicOverriddenMethod(); } + @SuppressWarnings("all") + public static int invokeOverriddenPublicMethodSnippet(SuperClass superClass) { + return superClass.publicOverriddenMethod(); + } + @SuppressWarnings("all") + public static int invokeOverriddenProtectedMethodSnippet(SuperClass superClass) { + return superClass.protectedOverriddenMethod(); + } private StructuredGraph getGraph(final String snippet) { return Debug.scope("InliningTest", new DebugDumpScope(snippet), new Callable() { diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Wed Jan 16 14:41:15 2013 +0100 @@ -38,6 +38,8 @@ import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*; import static com.oracle.graal.hotspot.snippets.AESCryptSubstitutions.DecryptBlockStubCall.*; import static com.oracle.graal.hotspot.snippets.AESCryptSubstitutions.EncryptBlockStubCall.*; +import static com.oracle.graal.hotspot.snippets.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*; +import static com.oracle.graal.hotspot.snippets.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*; import static com.oracle.graal.lir.amd64.AMD64Call.*; import com.oracle.graal.api.code.*; @@ -68,26 +70,26 @@ addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub, /* temps */ null, /* ret */ ret(Kind.Float), - /* arg0: a */ jarg(0, Kind.Float), - /* arg1: b */ jarg(1, Kind.Float)); + /* arg0: a */ javaCallingConvention(Kind.Float, + /* arg1: b */ Kind.Float)); addRuntimeCall(ARITHMETIC_DREM, config.arithmeticDremStub, /* temps */ null, /* ret */ ret(Kind.Double), - /* arg0: a */ jarg(0, Kind.Double), - /* arg1: b */ jarg(1, Kind.Double)); + /* arg0: a */ javaCallingConvention(Kind.Double, + /* arg1: b */ Kind.Double)); addRuntimeCall(MONITORENTER, config.monitorEnterStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: object */ jarg(0, Kind.Object), - /* arg1: lock */ jarg(1, word)); + /* arg0: object */ javaCallingConvention(Kind.Object, + /* arg1: lock */ word)); addRuntimeCall(MONITOREXIT, config.monitorExitStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: object */ jarg(0, Kind.Object), - /* arg1: lock */ jarg(1, word)); + /* arg0: object */ javaCallingConvention(Kind.Object, + /* arg1: lock */ word)); addRuntimeCall(NEW_ARRAY, 0L, /* temps */ null, @@ -126,34 +128,52 @@ addRuntimeCall(VM_ERROR, config.vmErrorStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: where */ jarg(0, Kind.Object), - /* arg1: format */ jarg(1, Kind.Object), - /* arg2: value */ jarg(2, Kind.Long)); + /* arg0: where */ javaCallingConvention(Kind.Object, + /* arg1: format */ Kind.Object, + /* arg2: value */ Kind.Long)); addRuntimeCall(IDENTITY_HASHCODE, config.identityHashCodeStub, /* temps */ null, /* ret */ rax.asValue(Kind.Int), - /* arg0: obj */ jarg(0, Kind.Object)); + /* arg0: obj */ javaCallingConvention(Kind.Object)); addRuntimeCall(THREAD_IS_INTERRUPTED, config.threadIsInterruptedStub, /* temps */ null, /* ret */ rax.asValue(Kind.Int), - /* arg0: thread */ jarg(0, Kind.Object), - /* arg1: clearInterrupted */ jarg(1, Kind.Boolean)); + /* arg0: thread */ javaCallingConvention(Kind.Object, + /* arg1: clearInterrupted */ Kind.Boolean)); addRuntimeCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: in */ carg(0, word), - /* arg1: out */ carg(1, word), - /* arg2: key */ carg(2, word)); + /* arg0: in */ nativeCallingConvention(word, + /* arg1: out */ word, + /* arg2: key */ word)); addRuntimeCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: in */ carg(0, word), - /* arg1: out */ carg(1, word), - /* arg2: key */ carg(2, word)); + /* arg0: in */ nativeCallingConvention(word, + /* arg1: out */ word, + /* arg2: key */ word)); + + addRuntimeCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: in */ nativeCallingConvention(word, + /* arg1: out */ word, + /* arg2: key */ word, + /* arg3: r */ word, + /* arg4: inLength */ Kind.Int)); + + addRuntimeCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: in */ nativeCallingConvention(word, + /* arg1: out */ word, + /* arg2: key */ word, + /* arg3: r */ word, + /* arg4: inLength */ Kind.Int)); } @Override diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Jan 16 14:41:15 2013 +0100 @@ -136,6 +136,7 @@ } else { // Compiling an intrinsic graph - must clone the graph graph = graph.copy(); + //System.out.println("compiling intrinsic " + method); } return graalRuntime.getCompiler().compileMethod(method, graph, graalRuntime.getCache(), plan, optimisticOpts); } @@ -192,4 +193,9 @@ return id < o.id ? -1 : (id > o.id ? 1 : 0); } + @Override + public String toString() { + return "Compilation[id=" + id + ", prio=" + priority + " " + MetaUtil.format("%H.%n(%p)", method) + + (entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "@" + entryBCI) + "]"; + } } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java Wed Jan 16 14:41:15 2013 +0100 @@ -49,12 +49,14 @@ return; } } - } else if (substituteMethod.getDeclaringClass() == AESCryptSubstitutions.class) { + } else if (substituteMethod.getDeclaringClass() == AESCryptSubstitutions.class || substituteMethod.getDeclaringClass() == CipherBlockChainingSubstitutions.class) { if (!config.useAESIntrinsics) { return; } assert config.aescryptEncryptBlockStub != 0L; assert config.aescryptDecryptBlockStub != 0L; + assert config.cipherBlockChainingEncryptAESCryptStub != 0L; + assert config.cipherBlockChainingDecryptAESCryptStub != 0L; } super.installSubstitution(originalMethod, substituteMethod); } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jan 16 14:41:15 2013 +0100 @@ -338,6 +338,8 @@ public long identityHashCodeStub; public long aescryptEncryptBlockStub; public long aescryptDecryptBlockStub; + public long cipherBlockChainingEncryptAESCryptStub; + public long cipherBlockChainingDecryptAESCryptStub; public int deoptReasonNullCheck; public int deoptReasonRangeCheck; diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Jan 16 14:41:15 2013 +0100 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.bridge; -import static com.oracle.graal.graph.FieldIntrospection.*; +import static com.oracle.graal.graph.UnsafeAccess.*; import java.io.*; import java.lang.reflect.*; diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Wed Jan 16 14:41:15 2013 +0100 @@ -379,6 +379,7 @@ Arrays.sort(ptypes); double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + assert notRecordedTypeProbability == 0 || entries == config.typeProfileWidth; return new JavaTypeProfile(notRecordedTypeProbability, ptypes); } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Jan 16 14:41:15 2013 +0100 @@ -166,14 +166,31 @@ return globalStubRegConfig.getReturnRegister(kind).asValue(kind); } - protected Value jarg(int index, Kind kind) { - RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU; - return globalStubRegConfig.getCallingConventionRegisters(RuntimeCall, flag)[index].asValue(kind); + protected Value[] javaCallingConvention(Kind... arguments) { + return callingConvention(arguments, RuntimeCall); + } + + protected Value[] nativeCallingConvention(Kind... arguments) { + return callingConvention(arguments, NativeCall); } - protected Value carg(int index, Kind kind) { - RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU; - return globalStubRegConfig.getCallingConventionRegisters(NativeCall, flag)[index].asValue(kind); + private Value[] callingConvention(Kind[] arguments, CallingConvention.Type type) { + Value[] result = new Value[arguments.length]; + + TargetDescription target = graalRuntime.getTarget(); + int currentStackOffset = 0; + for (int i = 0; i < arguments.length; i++) { + Kind kind = arguments[i]; + RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU; + Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, flag); + if (i < ccRegs.length) { + result[i] = ccRegs[i].asValue(kind); + } else { + result[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, false); + currentStackOffset += Math.max(target.sizeInBytes(kind), target.wordSize); + } + } + return result; } protected Value scratch(Kind kind) { @@ -189,17 +206,17 @@ addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: exception */ jarg(0, Kind.Object)); + /* arg0: exception */ javaCallingConvention(Kind.Object)); addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: long */ jarg(0, Kind.Long)); + /* arg0: long */ javaCallingConvention(Kind.Long)); addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: object */ jarg(0, Kind.Object)); + /* arg0: object */ javaCallingConvention(Kind.Object)); addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub, /* temps */ null, @@ -208,7 +225,7 @@ addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub, /* temps */ null, /* ret */ ret(Kind.Object), - /* arg0: index */ jarg(0, Kind.Int)); + /* arg0: index */ javaCallingConvention(Kind.Int)); addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub, /* temps */ null, @@ -221,38 +238,38 @@ addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub, /* temps */ null, /* ret */ ret(Kind.Double), - /* arg0: index */ jarg(0, Kind.Double)); + /* arg0: index */ javaCallingConvention(Kind.Double)); addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub, /* temps */ null, /* ret */ ret(Kind.Double), - /* arg0: index */ jarg(0, Kind.Double)); + /* arg0: index */ javaCallingConvention(Kind.Double)); addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub, /* temps */ null, /* ret */ ret(Kind.Double), - /* arg0: index */ jarg(0, Kind.Double)); + /* arg0: index */ javaCallingConvention(Kind.Double)); addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: typeChar */ jarg(0, Kind.Int), - /* arg1: value */ jarg(1, Kind.Long), - /* arg2: newline */ jarg(2, Kind.Boolean)); + /* arg0: typeChar */ javaCallingConvention(Kind.Int, + /* arg1: value */ Kind.Long, + /* arg2: newline */ Kind.Boolean)); addRuntimeCall(LOG_PRINTF, config.logPrintfStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: format */ jarg(0, Kind.Object), - /* arg1: value */ jarg(1, Kind.Long), - /* arg2: value */ jarg(2, Kind.Long), - /* arg3: value */ jarg(3, Kind.Long)); + /* arg0: format */ javaCallingConvention(Kind.Object, + /* arg1: value */ Kind.Long, + /* arg2: value */ Kind.Long, + /* arg3: value */ Kind.Long)); addRuntimeCall(LOG_OBJECT, config.logObjectStub, /* temps */ null, /* ret */ ret(Kind.Void), - /* arg0: object */ jarg(0, Kind.Object), - /* arg1: flags */ jarg(1, Kind.Int)); + /* arg0: object */ javaCallingConvention(Kind.Object, + /* arg1: flags */ Kind.Int)); } @@ -322,8 +339,9 @@ if (GraalOptions.IntrinsifyClassMethods) { installer.installSubstitutions(ClassSubstitutions.class); } - if (GraalOptions.IntrinsifyAESCryptMethods) { + if (GraalOptions.IntrinsifyAESMethods) { installer.installSubstitutions(AESCryptSubstitutions.class); + installer.installSubstitutions(CipherBlockChainingSubstitutions.class); } if (GraalOptions.IntrinsifyArrayCopy) { installer.installSnippets(ArrayCopySnippets.class); diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java Wed Jan 16 14:41:15 2013 +0100 @@ -44,13 +44,16 @@ @ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt") public class AESCryptSubstitutions { - private static final long kOffset; + static final long kOffset; + static final Class AESCryptClass; + static { try { // Need to use launcher class path as com.sun.crypto.provider.AESCrypt // is normally not on the boot class path ClassLoader cl = Launcher.getLauncher().getClassLoader(); - kOffset = UnsafeAccess.unsafe.objectFieldOffset(Class.forName("com.sun.crypto.provider.AESCrypt", true, cl).getDeclaredField("K")); + AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl); + kOffset = UnsafeAccess.unsafe.objectFieldOffset(AESCryptClass.getDeclaredField("K")); } catch (Exception ex) { throw new GraalInternalError(ex); } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java Wed Jan 16 14:41:15 2013 +0100 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.snippets; + +import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; +import com.oracle.graal.snippets.Snippet.Fold; +import com.oracle.graal.word.*; + +/** + * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods. + */ +@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining") +public class CipherBlockChainingSubstitutions { + + private static final long embeddedCipherOffset; + private static final long rOffset; + static { + try { + // Need to use launcher class path as com.sun.crypto.provider.AESCrypt + // is normally not on the boot class path + ClassLoader cl = Launcher.getLauncher().getClassLoader(); + embeddedCipherOffset = UnsafeAccess.unsafe.objectFieldOffset(Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl).getDeclaredField("embeddedCipher")); + rOffset = UnsafeAccess.unsafe.objectFieldOffset(Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl).getDeclaredField("r")); + } catch (Exception ex) { + throw new GraalInternalError(ex); + } + } + + @Fold + private static Class getAESCryptClass() { + return AESCryptSubstitutions.AESCryptClass; + } + + @MethodSubstitution(isStatic = false) + static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset)); + if (getAESCryptClass().isInstance(embeddedCipher)) { + Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset)).add(arrayBaseOffset(Kind.Byte)); + Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset)).add(arrayBaseOffset(Kind.Byte)); + Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); + Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); + EncryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); + } else { + encrypt(rcvr, in, inOffset, inLength, out, outOffset); + } + } + + @MethodSubstitution(isStatic = false) + static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset)); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset)).add(arrayBaseOffset(Kind.Byte)); + Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset)).add(arrayBaseOffset(Kind.Byte)); + Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); + Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); + DecryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); + } else { + decrypt(rcvr, in, inOffset, inLength, out, outOffset); + } + } + + public static class EncryptAESCryptStubCall extends FixedWithNextNode implements LIRGenLowerable { + + @Input private final ValueNode in; + @Input private final ValueNode out; + @Input private final ValueNode key; + @Input private final ValueNode r; + @Input private final ValueNode inLength; + + public static final Descriptor ENCRYPT = new Descriptor("encrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class); + + public EncryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) { + super(StampFactory.forVoid()); + this.in = in; + this.out = out; + this.key = key; + this.r = r; + this.inLength = inLength; + } + + @Override + public void generate(LIRGenerator gen) { + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(ENCRYPT); + gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength)); + } + + @NodeIntrinsic + public static native void call(Word in, Word out, Word key, Word r, int inLength); + } + + public static class DecryptAESCryptStubCall extends FixedWithNextNode implements LIRGenLowerable { + + @Input private final ValueNode in; + @Input private final ValueNode out; + @Input private final ValueNode key; + @Input private final ValueNode r; + @Input private final ValueNode inLength; + + public static final Descriptor DECRYPT = new Descriptor("decrypt", false, void.class, Word.class, Word.class, Word.class, Word.class, int.class); + + public DecryptAESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength) { + super(StampFactory.forVoid()); + this.in = in; + this.out = out; + this.key = key; + this.r = r; + this.inLength = inLength; + } + + @Override + public void generate(LIRGenerator gen) { + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(DECRYPT); + gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength)); + } + + @NodeIntrinsic + public static native void call(Word in, Word out, Word key, Word r, int inLength); + } +} diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/IntrinsifyArrayCopyPhase.java Wed Jan 16 14:41:15 2013 +0100 @@ -118,8 +118,10 @@ StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); assert snippetGraph != null : "ArrayCopySnippets should be installed"; hits = true; - Debug.log("%s > Intinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType()); + Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType()); InliningUtil.inline(methodCallTarget.invoke(), snippetGraph, false); + } else { + Debug.log("%s > not intrinsifying arraycopy", Debug.currentScope()); } } if (GraalOptions.OptCanonicalizer && hits) { diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Wed Jan 16 14:41:15 2013 +0100 @@ -43,6 +43,7 @@ public void setProbability(double probability) { assert probability >= 0 : String.format("Invalid argument %f, because the probability of a node must not be negative.", probability); this.probability = probability; + assert !Double.isNaN(probability); } protected void copyInto(FixedNode newNode) { diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Wed Jan 16 14:41:15 2013 +0100 @@ -57,6 +57,10 @@ void setProbability(double value); + double inliningRelevance(); + + void setInliningRelevance(double value); + boolean useForInlining(); void setUseForInlining(boolean value); diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Wed Jan 16 14:41:15 2013 +0100 @@ -42,6 +42,7 @@ private boolean polymorphic; private boolean useForInlining; private final long leafGraphId; + private double inliningRelevance; /** * Constructs a new Invoke instruction. @@ -56,6 +57,7 @@ this.leafGraphId = leafGraphId; this.polymorphic = false; this.useForInlining = true; + this.inliningRelevance = Double.NaN; } @Override @@ -88,6 +90,16 @@ } @Override + public double inliningRelevance() { + return inliningRelevance; + } + + @Override + public void setInliningRelevance(double value) { + inliningRelevance = value; + } + + @Override public long leafGraphId() { return leafGraphId; } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed Jan 16 14:41:15 2013 +0100 @@ -41,6 +41,7 @@ private boolean polymorphic; private boolean useForInlining; private final long leafGraphId; + private double inliningRelevance; public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci, long leafGraphId) { super(callTarget.returnStamp()); @@ -50,6 +51,7 @@ this.leafGraphId = leafGraphId; this.polymorphic = false; this.useForInlining = true; + this.inliningRelevance = Double.NaN; } public DispatchBeginNode exceptionEdge() { @@ -99,6 +101,16 @@ } @Override + public double inliningRelevance() { + return inliningRelevance; + } + + @Override + public void setInliningRelevance(double value) { + inliningRelevance = value; + } + + @Override public long leafGraphId() { return leafGraphId; } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java Wed Jan 16 14:41:15 2013 +0100 @@ -65,6 +65,8 @@ } } } + + new ComputeInliningRelevanceIterator(graph).apply(); } private void correctLoopFrequencies(Loop loop, double parentFrequency, BitSet visitedBlocks) { @@ -369,4 +371,74 @@ return probability; } } + + private static class ComputeInliningRelevanceIterator extends ScopedPostOrderNodeIterator { + private final HashMap lowestPathProbabilities; + private double currentProbability; + + public ComputeInliningRelevanceIterator(StructuredGraph graph) { + super(graph); + this.lowestPathProbabilities = computeLowestPathProbabilities(graph); + } + + @Override + protected void initializeScope() { + currentProbability = lowestPathProbabilities.get(currentScope); + } + + @Override + protected void invoke(Invoke invoke) { + assert !Double.isNaN(invoke.probability()); + invoke.setInliningRelevance(invoke.probability() / currentProbability); + } + + private HashMap computeLowestPathProbabilities(StructuredGraph graph) { + HashMap result = new HashMap<>(); + Deque scopes = getScopes(graph); + + while (!scopes.isEmpty()) { + FixedNode scopeBegin = scopes.pop(); + double probability = computeLowestPathProbability(scopeBegin); + result.put(scopeBegin, probability); + } + + return result; + } + + private static double computeLowestPathProbability(FixedNode scopeStart) { + double minPathProbability = scopeStart.probability(); + Node current = scopeStart; + + while (current != null) { + if (current instanceof ControlSplitNode) { + ControlSplitNode controlSplit = (ControlSplitNode) current; + current = getMaxProbabilitySux(controlSplit); + if (((FixedNode) current).probability() < minPathProbability) { + minPathProbability = ((FixedNode) current).probability(); + } + } else { + assert current.successors().count() <= 1; + current = current.successors().first(); + } + } + + return minPathProbability; + } + + private static Node getMaxProbabilitySux(ControlSplitNode controlSplit) { + Node maxSux = null; + double maxProbability = 0.0; + + // TODO: process recursively if we have multiple successors with same probability + for (Node sux: controlSplit.successors()) { + double probability = controlSplit.probability((BeginNode) sux); + if (probability > maxProbability) { + maxProbability = probability; + maxSux = sux; + } + } + + return maxSux; + } + } } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Wed Jan 16 14:41:15 2013 +0100 @@ -81,6 +81,7 @@ while (inliningPolicy.continueInlining(graph)) { final InlineInfo candidate = inliningPolicy.next(); + if (candidate != null) { boolean isWorthInlining = inliningPolicy.isWorthInlining(candidate); @@ -149,7 +150,8 @@ } private abstract static class AbstractInliningDecision implements InliningDecision { - public static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) { + protected static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) { + assert !Double.isNaN(info.weight()) && !Double.isNaN(maxSize); boolean success = info.weight() <= maxSize; if (GraalOptions.Debug) { String formatterString = success ? "(size %f <= %f)" : "(too large %f > %f)"; @@ -158,13 +160,21 @@ return success; } - public static boolean checkCompiledCodeSize(InlineInfo info) { + protected static boolean checkCompiledCodeSize(InlineInfo info) { if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) { InliningUtil.logNotInlinedMethod(info, "(CompiledCodeSize %d > %d)", info.compiledCodeSize(), GraalOptions.SmallCompiledCodeSize); return false; } return true; } + + protected static double getRelevance(Invoke invoke) { + if (GraalOptions.UseRelevanceBasedInlining) { + return invoke.inliningRelevance(); + } else { + return invoke.probability(); + } + } } private static class C1StaticSizeBasedInliningDecision extends AbstractInliningDecision { @@ -183,7 +193,7 @@ return false; } - double inlineWeight = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke().probability()); + double inlineWeight = Math.min(GraalOptions.RatioCapForInlining, getRelevance(info.invoke())); double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level()) * GraalOptions.MaximumInlineSize * inlineWeight; maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize); @@ -199,7 +209,8 @@ return false; } - double inlineBoost = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke().probability()) + Math.log10(Math.max(1, info.invoke().probability() - GraalOptions.ProbabilityCapForInlining + 1)); + double relevance = getRelevance(info.invoke()); + double inlineBoost = Math.min(GraalOptions.RatioCapForInlining, relevance) + Math.log10(Math.max(1, relevance - GraalOptions.RatioCapForInlining + 1)); double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level()) * GraalOptions.MaximumInlineSize; maxSize = maxSize + maxSize * inlineBoost; maxSize = Math.min(GraalOptions.MaximumGreedyInlineSize, Math.max(GraalOptions.MaximumTrivialSize, maxSize)); @@ -226,7 +237,7 @@ maxSize += transferredValues * GraalOptions.InliningBonusPerTransferredValue; } - double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke().probability()); + double inlineRatio = Math.min(GraalOptions.RatioCapForInlining, getRelevance(info.invoke())); maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level()) * maxSize * inlineRatio; maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize); @@ -240,7 +251,7 @@ assert GraalOptions.ProbabilityAnalysis; double maxSize = GraalOptions.MaximumGreedyInlineSize; - double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke().probability()); + double inlineRatio = Math.min(GraalOptions.RatioCapForInlining, getRelevance(info.invoke())); maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level()) * maxSize * inlineRatio; maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize); @@ -251,6 +262,10 @@ private static class BytecodeSizeBasedWeightComputationPolicy implements WeightComputationPolicy { @Override public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { + if (GraalOptions.AlwaysInlineIntrinsics && InliningUtil.canIntrinsify(method)) { + return 0; + } + double codeSize = method.getCodeSize(); if (preferredInvoke) { codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis; @@ -262,6 +277,10 @@ private static class ComplexityBasedWeightComputationPolicy implements WeightComputationPolicy { @Override public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { + if (GraalOptions.AlwaysInlineIntrinsics && InliningUtil.canIntrinsify(method)) { + return 0; + } + double complexity = method.getCompilationComplexity(); if (preferredInvoke) { complexity = complexity / GraalOptions.BoostInliningForEscapeAnalysis; @@ -273,6 +292,10 @@ private static class CompiledCodeSizeWeightComputationPolicy implements WeightComputationPolicy { @Override public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { + if (GraalOptions.AlwaysInlineIntrinsics && InliningUtil.canIntrinsify(method)) { + return 0; + } + int compiledCodeSize = method.getCompiledCodeSize(); return compiledCodeSize > 0 ? compiledCodeSize : method.getCodeSize() * 10; } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Jan 16 14:41:15 2013 +0100 @@ -84,7 +84,7 @@ private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, String msg) { if (shouldLogInliningDecision()) { - String methodString = invoke.callTarget() == null ? "callTarget=null" : invoke.callTarget().targetName(); + String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName()); logInliningDecision(methodString, false, msg, new Object[0]); } return false; @@ -200,11 +200,11 @@ return computeInliningLevel(invoke); } - protected static StructuredGraph getGraph(final Invoke invoke, final ResolvedJavaMethod concrete, final InliningCallback callback) { + protected static StructuredGraph getGraph(final ResolvedJavaMethod concrete, final InliningCallback callback) { return Debug.scope("GetInliningGraph", concrete, new Callable() { @Override public StructuredGraph call() throws Exception { - StructuredGraph result = getIntrinsicGraph(invoke, concrete); + StructuredGraph result = getIntrinsicGraph(concrete); if (result == null) { assert !Modifier.isNative(concrete.getModifiers()); result = callback.buildGraph(concrete); @@ -229,14 +229,14 @@ @Override public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, InliningCallback callback, Assumptions assumptions) { - StructuredGraph graph = getGraph(invoke, concrete, callback); + StructuredGraph graph = getGraph(concrete, callback); assumptions.recordMethodContents(concrete); InliningUtil.inline(invoke, graph, true); } @Override public int compiledCodeSize() { - return concrete.getCompiledCodeSize(); + return InliningUtil.compiledCodeSize(concrete); } @Override @@ -261,7 +261,7 @@ @Override public int compiledCodeSize() { - return concrete.getCompiledCodeSize(); + return InliningUtil.compiledCodeSize(concrete); } @Override @@ -283,7 +283,7 @@ graph.addBeforeFixed(invoke.node(), guard); graph.addBeforeFixed(invoke.node(), anchor); - StructuredGraph calleeGraph = getGraph(invoke, concrete, callback); + StructuredGraph calleeGraph = getGraph(concrete, callback); assumptions.recordMethodContents(concrete); InliningUtil.inline(invoke, calleeGraph, false); } @@ -320,7 +320,7 @@ public int compiledCodeSize() { int result = 0; for (ResolvedJavaMethod m: concretes) { - result += m.getCompiledCodeSize(); + result += InliningUtil.compiledCodeSize(m); } return result; } @@ -410,7 +410,7 @@ StructuredGraph[] calleeGraphs = new StructuredGraph[numberOfMethods]; for (int i = 0; i < numberOfMethods; i++) { ResolvedJavaMethod concrete = concretes.get(i); - calleeGraphs[i] = getGraph(invoke, concrete, callback); + calleeGraphs[i] = getGraph(concrete, callback); assumptions.recordMethodContents(concrete); } @@ -512,7 +512,7 @@ calleeEntryNode.setNext(invoke.node()); ResolvedJavaMethod concrete = concretes.get(0); - StructuredGraph calleeGraph = getGraph(invoke, concrete, callback); + StructuredGraph calleeGraph = getGraph(concrete, callback); assumptions.recordMethodContents(concrete); InliningUtil.inline(invoke, calleeGraph, false); } @@ -563,6 +563,7 @@ result.node().replaceFirstInput(result.callTarget(), callTarget); result.setUseForInlining(useForInlining); result.setProbability(probability); + result.setInliningRelevance(invoke.inliningRelevance() * probability); Kind kind = invoke.node().kind(); if (kind != Kind.Void) { @@ -757,6 +758,7 @@ return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.size()); } if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { + // due to filtering impossible types, notRecordedTypeProbability can be > 0 although the number of types is lower than what can be recorded in a type profile return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.size(), notRecordedTypeProbability * 100); } @@ -799,7 +801,7 @@ ProfiledType ptype = types[i]; ResolvedJavaType type = ptype.getType(); assert !type.isInterface() && (type.isArray() || !Modifier.isAbstract(type.getModifiers())) : type; - if (holder.isAssignableFrom(type)) { + if (!GraalOptions.OptFilterProfiledTypes || holder.isAssignableFrom(type)) { result.add(ptype); } } @@ -816,14 +818,14 @@ } private static boolean checkInvokeConditions(Invoke invoke) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { + if (invoke.predecessor() == null || !invoke.node().isAlive()) { + return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is dead code"); + } else if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has already been lowered, or has been created as a low-level node"); } else if (invoke.methodCallTarget().targetMethod() == null) { return logNotInlinedMethodAndReturnFalse(invoke, "target method is null"); } else if (invoke.stateAfter() == null) { return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has no after state"); - } else if (invoke.predecessor() == null || !invoke.node().isAlive()) { - return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is dead code"); } else if (!invoke.useForInlining()) { return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is marked to be not used for inlining"); } else if (invoke.methodCallTarget().receiver() != null && invoke.methodCallTarget().receiver().isConstant() && invoke.methodCallTarget().receiver().asConstant().isNull()) { @@ -836,7 +838,7 @@ private static boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) { if (method == null) { return logNotInlinedMethodAndReturnFalse(invoke, method, "the method is not resolved"); - } else if (Modifier.isNative(method.getModifiers()) && (!GraalOptions.Intrinsify || !InliningUtil.canIntrinsify(invoke, method))) { + } else if (Modifier.isNative(method.getModifiers()) && (!GraalOptions.Intrinsify || !InliningUtil.canIntrinsify(method))) { return logNotInlinedMethodAndReturnFalse(invoke, method, "it is a non-intrinsic native method"); } else if (Modifier.isAbstract(method.getModifiers())) { return logNotInlinedMethodAndReturnFalse(invoke, method, "it is an abstract method"); @@ -974,6 +976,14 @@ } fixed.setProbability(newProbability); } + if (node instanceof Invoke) { + Invoke newInvoke = (Invoke) node; + double newRelevance = newInvoke.inliningRelevance() * invoke.inliningRelevance(); + if (GraalOptions.LimitInlinedProbability) { + newRelevance = Math.min(newRelevance, invoke.inliningRelevance()); + } + newInvoke.setInliningRelevance(newRelevance); + } } if (node instanceof FrameState) { FrameState frameState = (FrameState) node; @@ -1032,13 +1042,20 @@ } } - public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target) { - StructuredGraph intrinsicGraph = getIntrinsicGraph(invoke, target); + public static boolean canIntrinsify(ResolvedJavaMethod target) { + StructuredGraph intrinsicGraph = getIntrinsicGraph(target); return intrinsicGraph != null; } - public static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target) { - assert invoke.node().isAlive(); + public static StructuredGraph getIntrinsicGraph(ResolvedJavaMethod target) { return (StructuredGraph) target.getCompilerStorage().get(Graph.class); } + + private static int compiledCodeSize(ResolvedJavaMethod target) { + if (GraalOptions.AlwaysInlineIntrinsics && canIntrinsify(target)) { + return 0; + } else { + return target.getCompiledCodeSize(); + } + } } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Wed Jan 16 14:41:15 2013 +0100 @@ -39,6 +39,7 @@ // inlining settings public static boolean Inline = true; + public static boolean AlwaysInlineIntrinsics = ____; public static boolean Intrinsify = true; static boolean InlineMonomorphicCalls = true; static boolean InlinePolymorphicCalls = true; @@ -52,6 +53,7 @@ public static int MaximumRecursiveInlining = 1; public static int SmallCompiledCodeSize = 2200; public static boolean LimitInlinedProbability = ____; + public static boolean UseRelevanceBasedInlining = ____; // WeightBasedInliningPolicy (0) public static float InliningSizePenaltyExp = 20; public static float MaximumInlineWeight = 1.25f; @@ -65,7 +67,7 @@ // Common options for inlining policies 1 to 4 public static float NestedInliningSizeRatio = 1f; public static float BoostInliningForEscapeAnalysis = 2f; - public static float ProbabilityCapForInlining = 1f; + public static float RatioCapForInlining = 1f; // escape analysis settings public static boolean PartialEscapeAnalysis = true; @@ -199,6 +201,7 @@ public static boolean OptFloatingReads = true; public static boolean OptTailDuplication = true; public static boolean OptEliminatePartiallyRedundantGuards = true; + public static boolean OptFilterProfiledTypes = true; // Intrinsification settings public static boolean IntrinsifyArrayCopy = true; @@ -208,7 +211,7 @@ public static boolean IntrinsifyThreadMethods = true; public static boolean IntrinsifyUnsafeMethods = true; public static boolean IntrinsifyMathMethods = true; - public static boolean IntrinsifyAESCryptMethods = true; + public static boolean IntrinsifyAESMethods = true; /** * Counts the various paths taken through snippets. diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java Wed Jan 16 14:41:15 2013 +0100 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.phases.graph; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; + +public abstract class ScopedPostOrderNodeIterator { + private final NodeBitMap processedNodes; + private final Deque nodeQueue; + private final NodeBitMap queuedNodes; + private final Deque scopes; + + protected FixedNode currentScope; + + public ScopedPostOrderNodeIterator(StructuredGraph graph) { + this.processedNodes = graph.createNodeBitMap(); + this.queuedNodes = graph.createNodeBitMap(); + this.nodeQueue = new ArrayDeque<>(); + this.scopes = getScopes(graph); + } + + public void apply() { + while (!scopes.isEmpty()) { + processedNodes.clearAll(); + queuedNodes.clearAll(); + this.currentScope = scopes.pop(); + initializeScope(); + processScope(); + } + } + + public void processScope() { + FixedNode current = currentScope; + do { + assert current.isAlive(); + processedNodes.mark(current); + + if (current instanceof Invoke) { + invoke((Invoke) current); + queueSuccessors(current); + current = nextQueuedNode(); + } else if (current instanceof LoopBeginNode) { + queueLoopBeginSuccessors((LoopBeginNode) current); + current = nextQueuedNode(); + } else if (current instanceof LoopExitNode) { + queueLoopExitSuccessors((LoopExitNode) current); + current = nextQueuedNode(); + } else if (current instanceof LoopEndNode) { + current = nextQueuedNode(); + } else if (current instanceof MergeNode) { + current = ((MergeNode) current).next(); + assert current != null; + } else if (current instanceof FixedWithNextNode) { + queueSuccessors(current); + current = nextQueuedNode(); + } else if (current instanceof EndNode) { + queueMerge((EndNode) current); + current = nextQueuedNode(); + } else if (current instanceof DeoptimizeNode) { + current = nextQueuedNode(); + } else if (current instanceof ReturnNode) { + current = nextQueuedNode(); + } else if (current instanceof UnwindNode) { + current = nextQueuedNode(); + } else if (current instanceof ControlSplitNode) { + queueSuccessors(current); + current = nextQueuedNode(); + } else { + assert false : current; + } + } while(current != null); + } + + protected void queueLoopBeginSuccessors(LoopBeginNode node) { + if (currentScope == node) { + queue(node.next()); + } else if (currentScope instanceof LoopBeginNode) { + // so we are currently processing loop A and found another loop B + // -> queue all loop exits of B except those that also exit loop A + for (LoopExitNode loopExit: node.loopExits()) { + if (!((LoopBeginNode) currentScope).loopExits().contains(loopExit)) { + queue(loopExit); + } + } + } else { + queue(node.loopExits()); + } + } + + protected void queueLoopExitSuccessors(LoopExitNode node) { + if (!(currentScope instanceof LoopBeginNode) || !((LoopBeginNode) currentScope).loopExits().contains(node)) { + queueSuccessors(node); + } + } + + protected Deque getScopes(StructuredGraph graph) { + Deque result = new ArrayDeque<>(); + result.push(graph.start()); + for (LoopBeginNode loopBegin: graph.getNodes(LoopBeginNode.class)) { + result.push(loopBegin); + } + return result; + } + + private void queueSuccessors(FixedNode x) { + queue(x.successors()); + } + + private void queue(NodeIterable iter) { + for (Node node : iter) { + queue(node); + } + } + + private void queue(Node node) { + if (node != null && !queuedNodes.isMarked(node)) { + queuedNodes.mark(node); + nodeQueue.addFirst((FixedNode) node); + } + } + + private FixedNode nextQueuedNode() { + if (nodeQueue.isEmpty()) { + return null; + } + + FixedNode result = nodeQueue.removeFirst(); + assert queuedNodes.isMarked(result); + return result; + } + + private void queueMerge(EndNode end) { + MergeNode merge = end.merge(); + if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) { + queuedNodes.mark(merge); + nodeQueue.add(merge); + } + } + + private boolean visitedAllEnds(MergeNode merge) { + for (int i = 0; i < merge.forwardEndCount(); i++) { + if (!processedNodes.isMarked(merge.forwardEndAt(i))) { + return false; + } + } + return true; + } + + protected abstract void initializeScope(); + protected abstract void invoke(Invoke invoke); +} diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java Wed Jan 16 14:41:15 2013 +0100 @@ -27,7 +27,7 @@ import com.oracle.graal.api.meta.*; /** - * Denotes a class that substitutes methods of another specified class with snippets. + * Denotes a class that substitutes methods of another specified class. * The substitute methods are exactly those annotated by {@link MethodSubstitution}. */ @Retention(RetentionPolicy.RUNTIME) @@ -35,7 +35,7 @@ public @interface ClassSubstitution { /** - * Specifies the substituted class. + * Specifies the original class. *

* If the default value is specified for this element, then a non-default * value must be given for the {@link #className()} element. @@ -43,9 +43,9 @@ Class value() default ClassSubstitution.class; /** - * Specifies the substituted class. + * Specifies the original class. *

- * This method is provided for cases where the substituted class + * This method is provided for cases where the original class * is not accessible (according to Java language access control rules). *

* If the default value is specified for this element, then a non-default @@ -54,29 +54,30 @@ String className() default ""; /** - * Denotes a substitute method. + * Denotes a substitute method. A substitute method can call the original/substituted + * method by making a recursive call to itself. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MethodSubstitution { /** - * Gets the name of the substituted method. + * Gets the name of the original method. *

* If the default value is specified for this element, then the - * name of the substituted method is same as the substitute method. + * name of the original method is same as the substitute method. */ String value() default ""; /** - * Determines if the substituted method is static. + * Determines if the original method is static. */ boolean isStatic() default true; /** - * Gets the {@linkplain Signature#getMethodDescriptor() signature} of the substituted method. + * Gets the {@linkplain Signature#getMethodDescriptor() signature} of the original method. *

* If the default value is specified for this element, then the - * signature of the substituted method is the same as the substitute method. + * signature of the original method is the same as the substitute method. */ String signature() default ""; } diff -r 729a79037bd5 -r 69318374c8d7 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Wed Jan 16 14:41:04 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Wed Jan 16 14:41:15 2013 +0100 @@ -56,6 +56,7 @@ private final TargetDescription target; private final Assumptions assumptions; private final BoxingMethodPool pool; + private final Thread owner; /** * A graph cache used by this installer to avoid using the compiler @@ -71,6 +72,7 @@ this.assumptions = assumptions; this.pool = new BoxingMethodPool(runtime); this.graphCache = new HashMap<>(); + this.owner = Thread.currentThread(); } /** @@ -101,6 +103,7 @@ * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each original method. */ public void installSubstitutions(Class substitutions) { + assert owner == Thread.currentThread() : "substitution installation must be single threaded"; ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class); for (Method substituteMethod : substitutions.getDeclaredMethods()) { MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); @@ -122,6 +125,11 @@ } } + // These fields are used to detect calls from the substitute method to the original method. + ResolvedJavaMethod substitute; + ResolvedJavaMethod original; + boolean substituteCallsOriginal; + /** * Installs a method substitution. * @@ -129,12 +137,18 @@ * @param substituteMethod the substitute method */ protected void installSubstitution(Method originalMethod, Method substituteMethod) { - ResolvedJavaMethod substitute = runtime.lookupJavaMethod(substituteMethod); - ResolvedJavaMethod original = runtime.lookupJavaMethod(originalMethod); - //System.out.println("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); - StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute), true); - Object oldValue = original.getCompilerStorage().put(Graph.class, graph); - assert oldValue == null; + substitute = runtime.lookupJavaMethod(substituteMethod); + original = runtime.lookupJavaMethod(originalMethod); + try { + //System.out.println("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); + StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute), true); + Object oldValue = original.getCompilerStorage().put(Graph.class, graph); + assert oldValue == null; + } finally { + substitute = null; + original = null; + substituteCallsOriginal = false; + } } private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { @@ -161,7 +175,7 @@ new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph); - if (isSubstitution) { + if (isSubstitution && !substituteCallsOriginal) { // TODO (ds) remove the constraint of only processing substitutions // once issues with the arraycopy snippets have been resolved new SnippetFrameStateCleanupPhase().apply(graph); @@ -203,14 +217,29 @@ for (Invoke invoke : graph.getInvokes()) { MethodCallTargetNode callTarget = invoke.methodCallTarget(); ResolvedJavaMethod callee = callTarget.targetMethod(); - if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, method)) { - StructuredGraph targetGraph = parseGraph(callee, policy); - InliningUtil.inline(invoke, targetGraph, true); + if (callee == substitute) { + final StructuredGraph originalGraph = new StructuredGraph(original); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); + InliningUtil.inline(invoke, originalGraph, true); + + // TODO the inlined frame states still show the call from the substitute to the original. + // If this poses a problem, a phase should added to fix up these frame states. + Debug.dump(graph, "after inlining %s", callee); if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); new CanonicalizerPhase(target, runtime, assumptions).apply(graph); } + substituteCallsOriginal = true; + } else { + if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, method)) { + StructuredGraph targetGraph = parseGraph(callee, policy); + InliningUtil.inline(invoke, targetGraph, true); + Debug.dump(graph, "after inlining %s", callee); + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } + } } } diff -r 729a79037bd5 -r 69318374c8d7 src/cpu/x86/vm/graalRuntime_x86.cpp --- a/src/cpu/x86/vm/graalRuntime_x86.cpp Wed Jan 16 14:41:04 2013 +0100 +++ b/src/cpu/x86/vm/graalRuntime_x86.cpp Wed Jan 16 14:41:15 2013 +0100 @@ -188,25 +188,46 @@ int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3, Register arg4) { #ifdef _LP64 - // if there is any conflict use the stack - if (arg1 == c_rarg2 || arg1 == c_rarg3 || arg1 == c_rarg4 || - arg2 == c_rarg1 || arg2 == c_rarg3 || arg2 == c_rarg4 || - arg3 == c_rarg1 || arg3 == c_rarg2 || arg3 == c_rarg4 || - arg4 == c_rarg1 || arg4 == c_rarg2 || arg4 == c_rarg3) { - push(arg4); - push(arg3); - push(arg2); - push(arg1); - pop(c_rarg1); - pop(c_rarg2); - pop(c_rarg3); - pop(c_rarg4); - } else { - mov(c_rarg1, arg1); - mov(c_rarg2, arg2); - mov(c_rarg3, arg3); - mov(c_rarg4, arg4); - } + #ifdef _WIN64 + // on windows we only have the registers c_rarg0 to c_rarg3 for transferring parameters -> remaining parameters are on the stack + if (arg1 == c_rarg2 || arg1 == c_rarg3 || + arg2 == c_rarg1 || arg2 == c_rarg3 || + arg3 == c_rarg1 || arg3 == c_rarg2 || + arg4 == c_rarg1 || arg4 == c_rarg2) { + push(arg4); + push(arg3); + push(arg2); + push(arg1); + pop(c_rarg1); + pop(c_rarg2); + pop(c_rarg3); + } else { + mov(c_rarg1, arg1); + mov(c_rarg2, arg2); + mov(c_rarg3, arg3); + push(arg4); + } + #else + // if there is any conflict use the stack + if (arg1 == c_rarg2 || arg1 == c_rarg3 || arg1 == c_rarg4 || + arg2 == c_rarg1 || arg2 == c_rarg3 || arg2 == c_rarg4 || + arg3 == c_rarg1 || arg3 == c_rarg2 || arg3 == c_rarg4 || + arg4 == c_rarg1 || arg4 == c_rarg2 || arg4 == c_rarg3) { + push(arg4); + push(arg3); + push(arg2); + push(arg1); + pop(c_rarg1); + pop(c_rarg2); + pop(c_rarg3); + pop(c_rarg4); + } else { + mov(c_rarg1, arg1); + mov(c_rarg2, arg2); + mov(c_rarg3, arg3); + mov(c_rarg4, arg4); + } + #endif #else push(arg4); push(arg3); diff -r 729a79037bd5 -r 69318374c8d7 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Jan 16 14:41:04 2013 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Jan 16 14:41:15 2013 +0100 @@ -736,6 +736,8 @@ set_long("logPrintfStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_printf_id))); set_long("aescryptEncryptBlockStub", VmIds::addStub(StubRoutines::aescrypt_encryptBlock())); set_long("aescryptDecryptBlockStub", VmIds::addStub(StubRoutines::aescrypt_decryptBlock())); + set_long("cipherBlockChainingEncryptAESCryptStub", VmIds::addStub(StubRoutines::cipherBlockChaining_encryptAESCrypt())); + set_long("cipherBlockChainingDecryptAESCryptStub", VmIds::addStub(StubRoutines::cipherBlockChaining_decryptAESCrypt())); set_int("deoptReasonNone", Deoptimization::Reason_none); set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check); diff -r 729a79037bd5 -r 69318374c8d7 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Wed Jan 16 14:41:04 2013 +0100 +++ b/src/share/vm/graal/graalRuntime.cpp Wed Jan 16 14:41:15 2013 +0100 @@ -588,11 +588,9 @@ JRT_ENTRY(jboolean, GraalRuntime::graal_thread_is_interrupted(JavaThread* thread, oop receiver, jboolean clear_interrupted)) // Ensure that the C++ Thread and OSThread structures aren't freed before we operate Handle receiverHandle(thread, receiver); - JRT_BLOCK - MutexLockerEx ml(thread->threadObj() == receiver ? NULL : Threads_lock); - JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); - return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0); - JRT_BLOCK_END + MutexLockerEx ml(thread->threadObj() == receiver ? NULL : Threads_lock); + JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); + return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0); JRT_END // JVM_InitializeGraalRuntime